import { Page } from 'web/components/page' import { Grid, _ as r } from 'gridjs-react' import 'gridjs/dist/theme/mermaid.css' import { html } from 'gridjs' import dayjs from 'dayjs' import { usePrivateUsers, useUsers } from 'web/hooks/use-users' import Custom404 from './404' import { useContracts } from 'web/hooks/use-contracts' import { mapKeys } from 'lodash' import { useAdmin } from 'web/hooks/use-admin' import { contractPath } from 'web/lib/firebase/contracts' import { redirectIfLoggedOut } from 'web/lib/firebase/server-auth' import { useEffect, useState } from 'react' import { getFirstDayProfit } from 'web/lib/firebase/users' export const getServerSideProps = redirectIfLoggedOut('/') function avatarHtml(avatarUrl: string) { return `` } function UsersTable() { const users = useUsers() const privateUsers = usePrivateUsers() // Map private users by user id const privateUsersById = mapKeys(privateUsers, 'id') const [profitByUser, setProfitByUser] = useState<{ [userId: string]: number }>({}) useEffect(() => { Promise.all(users.map((user) => getFirstDayProfit(user.id))).then( (firstDayProfits) => { setProfitByUser( Object.fromEntries( users.map((user, i) => [ user.id, user.profitCached.allTime - firstDayProfits[i], ]) ) ) } ) // eslint-disable-next-line react-hooks/exhaustive-deps }, [users.map((user) => user.id).join(',')]) // For each user, set their email from the PrivateUser const fullUsers = users .map((user) => { return { email: privateUsersById[user.id]?.email, profit: profitByUser[user.id] ?? 0, ip: privateUsersById[user.id]?.initialIpAddress, ...user, } }) .sort((a, b) => b.createdTime - a.createdTime) function exportCsv() { const lines = [['Email', 'Name', 'Balance', 'Profit', 'IP Address']].concat( fullUsers.map((u) => [ u.email ?? '', u.name, Math.round(u.balance).toString(), Math.round(profitByUser[u.id] ?? 0).toString(), u.ip ?? '', ]) ) const csv = lines.map((line) => line.join(', ')).join('\n') const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = 'manifold-users.csv' a.click() URL.revokeObjectURL(url) } return ( <> html(avatarHtml(cell as string)), }, { id: 'username', name: 'Username', formatter: (cell) => html(`@${cell}`), }, { id: 'name', name: 'Name', formatter: (cell) => html(`${cell}`), }, { id: 'email', name: 'Email', }, { id: 'createdTime', name: 'Created', formatter: (cell) => html( `${dayjs(cell as number).format( 'MMM D, h:mma' )}` ), }, { id: 'balance', name: 'Balance', formatter: (cell) => (cell as number).toFixed(0), }, { id: 'profit', name: 'profit', formatter: (cell) => (cell as number).toFixed(0), }, { id: 'id', name: 'ID', formatter: (cell) => html(`${cell}`), }, ]} search={true} sort={true} pagination={{ enabled: true, limit: 25, }} /> ) } function ContractsTable() { const contracts = useContracts() ?? [] // Sort users by createdTime descending, by default const displayContracts = contracts .sort((a, b) => b.createdTime - a.createdTime) .map((contract) => { // Render a clickable question. See https://gridjs.io/docs/examples/react-cells for docs const questionLink = r(
{contract.question}
) return { questionLink, ...contract } }) return ( html(`@${cell}`), }, { id: 'questionLink', name: 'Question', }, { id: 'volume24Hours', name: '24h vol', formatter: (cell) => (cell as number).toFixed(0), }, { id: 'createdTime', name: 'Created time', formatter: (cell) => html( `${dayjs(cell as number).format( 'MMM D, h:mma' )}` ), }, { id: 'closeTime', name: 'Close time', formatter: (cell) => html( `${dayjs(cell as number).format( 'MMM D, h:mma' )}` ), }, { id: 'resolvedTime', name: 'Resolved time', formatter: (cell) => html( `${dayjs(cell as number).format( 'MMM D, h:mma' )}` ), }, { id: 'visibility', name: 'Visibility', formatter: (cell) => cell, }, { id: 'id', name: 'ID', formatter: (cell) => html(`${cell}`), }, ]} search={true} sort={true} pagination={{ enabled: true, limit: 25, }} /> ) } export default function Admin() { return useAdmin() ? ( ) : ( ) }