mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-04-08 08:39:36 -04:00
Add nice stats
This commit is contained in:
@@ -54,6 +54,7 @@ import swaggerUi from "swagger-ui-express"
|
||||
import * as fs from "fs"
|
||||
import {sendSearchNotifications} from "api/send-search-notifications";
|
||||
import {sendDiscordMessage} from "common/discord/core";
|
||||
import {getMessagesCount} from "api/get-messages-count";
|
||||
|
||||
const allowCorsUnrestricted: RequestHandler = cors({})
|
||||
|
||||
@@ -165,6 +166,7 @@ const handlers: { [k in APIPath]: APIHandler<k> } = {
|
||||
'get-channel-messages': getChannelMessages,
|
||||
'get-channel-seen-time': getLastSeenChannelTime,
|
||||
'set-channel-seen-time': setChannelLastSeenTime,
|
||||
'get-messages-count': getMessagesCount,
|
||||
}
|
||||
|
||||
Object.entries(handlers).forEach(([path, handler]) => {
|
||||
|
||||
18
backend/api/src/get-messages-count.ts
Normal file
18
backend/api/src/get-messages-count.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {APIHandler} from './helpers/endpoint'
|
||||
import {createSupabaseDirectClient} from "shared/supabase/init";
|
||||
|
||||
export const getMessagesCount: APIHandler<'get-messages-count'> = async (_, auth) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
const result = await pg.one(
|
||||
`
|
||||
SELECT COUNT(*) AS count
|
||||
FROM private_user_messages;
|
||||
`,
|
||||
[]
|
||||
);
|
||||
const count = Number(result.count);
|
||||
console.debug('private_user_messages count:', count);
|
||||
return {
|
||||
count: count,
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,19 @@ import {
|
||||
baseProfilesSchema,
|
||||
arraybeSchema,
|
||||
} from 'common/api/zod-types'
|
||||
import { PrivateChatMessage } from 'common/chat-message'
|
||||
import { CompatibilityScore } from 'common/love/compatibility-score'
|
||||
import { MAX_COMPATIBILITY_QUESTION_LENGTH } from 'common/love/constants'
|
||||
import { Profile, ProfileRow } from 'common/love/profile'
|
||||
import { Row } from 'common/supabase/utils'
|
||||
import { PrivateUser, User } from 'common/user'
|
||||
import { z } from 'zod'
|
||||
import { LikeData, ShipData } from './love-types'
|
||||
import { DisplayUser, FullUser } from './user-types'
|
||||
import { PrivateMessageChannel } from 'common/supabase/private-messages'
|
||||
import { Notification } from 'common/notifications'
|
||||
import { arrify } from 'common/util/array'
|
||||
import { notification_preference } from 'common/user-notification-preferences'
|
||||
import {PrivateChatMessage} from 'common/chat-message'
|
||||
import {CompatibilityScore} from 'common/love/compatibility-score'
|
||||
import {MAX_COMPATIBILITY_QUESTION_LENGTH} from 'common/love/constants'
|
||||
import {Profile, ProfileRow} from 'common/love/profile'
|
||||
import {Row} from 'common/supabase/utils'
|
||||
import {PrivateUser, User} from 'common/user'
|
||||
import {z} from 'zod'
|
||||
import {LikeData, ShipData} from './love-types'
|
||||
import {DisplayUser, FullUser} from './user-types'
|
||||
import {PrivateMessageChannel} from 'common/supabase/private-messages'
|
||||
import {Notification} from 'common/notifications'
|
||||
import {arrify} from 'common/util/array'
|
||||
import {notification_preference} from 'common/user-notification-preferences'
|
||||
|
||||
// mqp: very unscientific, just balancing our willingness to accept load
|
||||
// with user willingness to put up with stale data
|
||||
@@ -59,12 +59,12 @@ export const API = (_apiTypeCheck = {
|
||||
'user/by-id/:id/block': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
props: z.object({ id: z.string() }).strict(),
|
||||
props: z.object({id: z.string()}).strict(),
|
||||
},
|
||||
'user/by-id/:id/unblock': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
props: z.object({ id: z.string() }).strict(),
|
||||
props: z.object({id: z.string()}).strict(),
|
||||
},
|
||||
'ban-user': {
|
||||
method: 'POST',
|
||||
@@ -176,28 +176,28 @@ export const API = (_apiTypeCheck = {
|
||||
authed: false,
|
||||
cache: DEFAULT_CACHE_STRATEGY,
|
||||
returns: {} as FullUser,
|
||||
props: z.object({ username: z.string() }).strict(),
|
||||
props: z.object({username: z.string()}).strict(),
|
||||
},
|
||||
'user/:username/lite': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
cache: DEFAULT_CACHE_STRATEGY,
|
||||
returns: {} as DisplayUser,
|
||||
props: z.object({ username: z.string() }).strict(),
|
||||
props: z.object({username: z.string()}).strict(),
|
||||
},
|
||||
'user/by-id/:id': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
cache: DEFAULT_CACHE_STRATEGY,
|
||||
returns: {} as FullUser,
|
||||
props: z.object({ id: z.string() }).strict(),
|
||||
props: z.object({id: z.string()}).strict(),
|
||||
},
|
||||
'user/by-id/:id/lite': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
cache: DEFAULT_CACHE_STRATEGY,
|
||||
returns: {} as DisplayUser,
|
||||
props: z.object({ id: z.string() }).strict(),
|
||||
props: z.object({id: z.string()}).strict(),
|
||||
},
|
||||
'search-users': {
|
||||
method: 'GET',
|
||||
@@ -215,7 +215,7 @@ export const API = (_apiTypeCheck = {
|
||||
'compatible-profiles': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
props: z.object({ userId: z.string() }),
|
||||
props: z.object({userId: z.string()}),
|
||||
returns: {} as {
|
||||
profile: Profile
|
||||
compatibleProfiles: Profile[]
|
||||
@@ -227,7 +227,7 @@ export const API = (_apiTypeCheck = {
|
||||
'remove-pinned-photo': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
returns: { success: true },
|
||||
returns: {success: true},
|
||||
props: z
|
||||
.object({
|
||||
userId: z.string(),
|
||||
@@ -338,7 +338,7 @@ export const API = (_apiTypeCheck = {
|
||||
'get-profile-answers': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
props: z.object({ userId: z.string() }).strict(),
|
||||
props: z.object({userId: z.string()}).strict(),
|
||||
returns: {} as {
|
||||
status: 'success'
|
||||
answers: Row<'love_compatibility_answers'>[]
|
||||
@@ -477,6 +477,12 @@ export const API = (_apiTypeCheck = {
|
||||
radius: z.number().min(1).max(500),
|
||||
}),
|
||||
},
|
||||
'get-messages-count': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
props: z.object({}),
|
||||
returns: {} as { count: number },
|
||||
},
|
||||
} as const)
|
||||
|
||||
export type APIPath = keyof typeof API
|
||||
@@ -488,8 +494,8 @@ export type ValidatedAPIParams<N extends APIPath> = z.output<
|
||||
>
|
||||
|
||||
export type APIResponse<N extends APIPath> = APISchema<N> extends {
|
||||
returns: Record<string, any>
|
||||
}
|
||||
returns: Record<string, any>
|
||||
}
|
||||
? APISchema<N>['returns']
|
||||
: void
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export const Card = forwardRef(function Card(
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-canvas-0 border-ink-300 cursor-pointer rounded-lg border transition-shadow hover:shadow-md focus:shadow-md',
|
||||
'bg-canvas-0 border-ink-300 rounded-lg border transition-shadow hover:shadow-md focus:shadow-md',
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {db} from './db'
|
||||
import {run} from 'common/supabase/utils'
|
||||
import {APIError, api} from 'web/lib/api'
|
||||
import {api, APIError} from 'web/lib/api'
|
||||
import {unauthedApi} from 'common/util/api'
|
||||
import type {DisplayUser} from 'common/api/user-types'
|
||||
import {MIN_BIO_LENGTH} from "common/constants";
|
||||
@@ -75,4 +75,21 @@ export async function getProfilesWithBioCreations() {
|
||||
.order('created_time')
|
||||
)
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCount(table: string) {
|
||||
if (table == 'private_user_messages') {
|
||||
const result = await api('get-messages-count')
|
||||
return result.count
|
||||
}
|
||||
const {count} = await run(
|
||||
db
|
||||
.from(table)
|
||||
.select('*', {count: 'exact', head: true})
|
||||
)
|
||||
return count;
|
||||
}
|
||||
|
||||
// export async function getNumberProfiles() {
|
||||
// return await getCount('profiles');
|
||||
// }
|
||||
|
||||
@@ -1,13 +1,61 @@
|
||||
import {LovePage} from "web/components/love-page";
|
||||
import ChartMembers from "web/components/widgets/charts";
|
||||
import {getCount} from "web/lib/supabase/users";
|
||||
import {useEffect, useState} from "react";
|
||||
import StatBox from "web/components/widgets/stat-box";
|
||||
import clsx from "clsx";
|
||||
import {Col} from "web/components/layout/col";
|
||||
|
||||
export default function Charts() {
|
||||
const [data, setData] = useState<Record<string, number | null>>({})
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
const tables = [
|
||||
'profiles',
|
||||
'bookmarked_searches',
|
||||
'private_user_message_channels',
|
||||
'private_user_messages',
|
||||
'profile_comments',
|
||||
'love_compatibility_answers',
|
||||
] as const
|
||||
|
||||
const settled = await Promise.allSettled(
|
||||
tables.map((t) => getCount(t))
|
||||
)
|
||||
|
||||
const result: Record<string, number | null> = {}
|
||||
settled.forEach((res, i) => {
|
||||
const key = tables[i]
|
||||
if (res.status === 'fulfilled') result[key] = res.value
|
||||
else result[key] = null
|
||||
})
|
||||
|
||||
setData(result)
|
||||
}
|
||||
|
||||
void load()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<LovePage
|
||||
trackPageView={'charts'}
|
||||
>
|
||||
<LovePage trackPageView={'charts'}>
|
||||
<h1 className="text-3xl font-semibold text-center mb-6">Community Growth over Time</h1>
|
||||
<ChartMembers/>
|
||||
<Col className={'mx-4 mb-8'}>
|
||||
<ChartMembers/>
|
||||
<Col
|
||||
className={clsx(
|
||||
'pb-[58px] lg:pb-0', // bottom bar padding
|
||||
'text-ink-1000 mx-auto w-full grid grid-cols-1 gap-8 max-w-3xl sm:grid-cols-2 lg:min-h-0 lg:pt-4 mt-4',
|
||||
)}
|
||||
>
|
||||
{!!data.profiles && <StatBox value={data.profiles} label={'Members'} />}
|
||||
{!!data.bookmarked_searches && <StatBox value={data.bookmarked_searches} label={'Searches Bookmarked'} />}
|
||||
{!!data.private_user_message_channels && <StatBox value={data.private_user_message_channels} label={'Discussions'} />}
|
||||
{!!data.private_user_messages && <StatBox value={data.private_user_messages} label={'Messages'} />}
|
||||
{!!data.profile_comments && <StatBox value={data.profile_comments} label={'Endorsements'} />}
|
||||
{!!data.love_compatibility_answers && <StatBox value={data.love_compatibility_answers} label={'Prompts Answered'} />}
|
||||
</Col>
|
||||
</Col>
|
||||
</LovePage>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user