diff --git a/back-end/types/misc.ts b/back-end/types/misc.ts index 697f698..fa36021 100644 --- a/back-end/types/misc.ts +++ b/back-end/types/misc.ts @@ -34,4 +34,6 @@ export const PURCHASE_TYPES_BY_TYPE = objectFromEntries( TABLE_ROWS.purchase_type.map(r => [r.purchase_type_id, r]) ) -export type PurchaseType = keyof typeof PURCHASE_TYPES_BY_TYPE \ No newline at end of file +export type PurchaseType = keyof typeof PURCHASE_TYPES_BY_TYPE + +export type PurchaseCountMap = {[key in PurchaseType]: number} diff --git a/back-end/types/route-types.ts b/back-end/types/route-types.ts index 1173698..c1f07c5 100644 --- a/back-end/types/route-types.ts +++ b/back-end/types/route-types.ts @@ -1,5 +1,5 @@ import { TABLE_ROWS, Tables } from "./db-types.ts" -import { AttendeeInfo, FullAccountInfo } from "./misc.ts" +import {AttendeeInfo, FullAccountInfo, PurchaseCountMap } from "./misc.ts" export type Routes = { '/account': { @@ -108,7 +108,7 @@ export type Routes = { '/stats': { method: 'get', body: undefined, - response: { accounts: number, purchases: {[key: string]: number} } + response: { accounts: number, purchases: PurchaseCountMap } } } diff --git a/back-end/utils/db.ts b/back-end/utils/db.ts index a64657d..7e45440 100644 --- a/back-end/utils/db.ts +++ b/back-end/utils/db.ts @@ -4,9 +4,10 @@ import { REFERRAL_MAXES, } from './constants.ts' import { TableName, Tables } from '../types/db-types.ts' -import { Maybe } from "../types/misc.ts" -import { _format } from 'https://deno.land/std@0.160.0/path/_util.ts' +import {Maybe, PurchaseCountMap } from "../types/misc.ts" import { WhereClause, queryTableQuery, insertTableQuery, updateTableQuery, deleteTableQuery } from './db-inner.ts' +import {Purchases} from "../types/route-types.ts"; +import {objectEntries} from "./misc.ts"; const url = new URL(env.DB_URL) @@ -220,22 +221,22 @@ export async function accountReferralStatus( export async function festivalStats( db: Pick, -): Promise<{ accounts: number, purchaseCounts: {[key: string]: number} }> { +): Promise<{ accounts: number, purchases: PurchaseCountMap> { const accountRes = (await db.queryObject< - & Pick + number >` SELECT count(*) as accounts from account where password_hash is not null `).rows - const purchaseRes = (await db.queryObject< - & Pick + const purchaseRes: Purchases = (await db.queryObject< + Record >` - SELECT purchase_type_id, count(*) FROM purchase GROUP BY purchase_type_id; + SELECT purchase_type_id, count(*) as purchase_count FROM purchase GROUP BY purchase_type_id; `).rows - const purchases = {} - for (let [key, value] of Object.entries(purchaseRes)) { - purchases[value['purchase_type_id']] = Number(value['count']) + const purchases : PurchaseCountMap = {} + for (const [key, value] of objectEntries(purchaseRes)) { + purchases[value['purchase_type_id']] = Number(value['purchase_count']) } return { diff --git a/front-end/src/components/Stats.tsx b/front-end/src/components/Stats.tsx index a455718..339eaa2 100644 --- a/front-end/src/components/Stats.tsx +++ b/front-end/src/components/Stats.tsx @@ -5,6 +5,13 @@ import { useRequest } from '../mobx/hooks' import Col from './core/Col' import Store from "../Store.ts"; import {vibefetch} from "../vibefetch.ts"; +import LoadingDots from "./core/LoadingDots.tsx"; +import { + PURCHASE_TYPES_BY_TYPE, + PurchaseCountMap, + PurchaseType +} from "../../../back-end/types/misc.ts"; +import {objectKeys} from "../../../back-end/utils/misc.ts"; export default observer(() => { const stats = useRequest(async () => { @@ -19,34 +26,40 @@ export default observer(() => { undefined ) - return response ?? undefined + return response }) - const purchases = stats.state.result ? stats.state.result?.purchases : {} + const purchases = stats.state.result?.purchases ?? ({} as PurchaseCountMap) const purchaseTable = Object.keys(purchases).length > 0 ? ( - {Object.keys(purchases).map((key) => { + {objectKeys(purchases).map((key) => { return ( - - + + ); })}
{key}{purchases[key]}{PURCHASE_TYPES_BY_TYPE[key].description}{purchases[key]}
- ) :
[loading]
+ ) :
return (

Stats

-
- Accounts Created: {stats.state.result?.accounts ?? 'loading'} -
-
- {purchaseTable} -
+ + {stats.state.kind === 'loading' ? : ( + <> +
+ Accounts Created: {stats.state.result?.accounts} +
+
+

Purchases

+ {purchaseTable} +
+ + )} ) })