Skip to content

Commit 5e7c0dd

Browse files
authored
Log fix (#122)
Add pagination to global log
1 parent 2e53003 commit 5e7c0dd

File tree

8 files changed

+93
-35
lines changed

8 files changed

+93
-35
lines changed

src/components/activity/ActivityTable.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,19 @@ interface ActivityTableProps {
1010
tickets: TicketWithNames[];
1111
title: string;
1212
shouldShowCreatedBy: boolean;
13+
shouldShowHelpedBy: boolean;
1314
}
1415

1516
/**
1617
* Table that displays a list of tickets. This will either be tickets that the user has
1718
* helped or tickets that the user has created.
1819
*/
1920
const ActivityTable = (props: ActivityTableProps) => {
20-
const { tickets, title, shouldShowCreatedBy } = props;
21-
const columns = useMemo(() => getActivityTableColumns(title, shouldShowCreatedBy), [shouldShowCreatedBy, title]);
21+
const { tickets, title, shouldShowCreatedBy, shouldShowHelpedBy } = props;
22+
const columns = useMemo(
23+
() => getActivityTableColumns(title, shouldShowCreatedBy, shouldShowHelpedBy),
24+
[shouldShowCreatedBy, shouldShowHelpedBy, title],
25+
);
2226
const data = useMemo(() => addDurationToTickets(tickets), [tickets]);
2327

2428
const {

src/components/activity/ActivityView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const ActivityView = (props: ActivityViewProps) => {
3535
tickets={helpedTickets}
3636
title={`${helpedTickets.length} helped tickets`}
3737
shouldShowCreatedBy={true}
38+
shouldShowHelpedBy={false}
3839
/>
3940
</Collapse>
4041
</Box>
@@ -45,6 +46,7 @@ const ActivityView = (props: ActivityViewProps) => {
4546
tickets={createdTickets}
4647
title={`${createdTickets.length} created tickets`}
4748
shouldShowCreatedBy={false}
49+
shouldShowHelpedBy={true}
4850
/>
4951
</Collapse>
5052
</Box>

src/components/activity/GlobalLog.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ const GlobalLog = () => {
5757
<Text fontSize='3xl' fontWeight='semibold' mb={3}>
5858
Global Log
5959
</Text>
60+
<Text mb={3} display='inherit'>
61+
<Link href='/activity/global'>
62+
<Text _hover={{ cursor: 'pointer' }} fontStyle='italic'>Click here to view all tickets&nbsp;</Text>
63+
</Link>
64+
or search for a user&lsquo;s log below
65+
</Text>
6066
<Input id='email' placeholder='Email' onChange={e => setEmail(e.target.value)} />
6167
<Button mb={2} mt={2} colorScheme='yellow' disabled={!email.match(EMAIL_REGEX)} onClick={handleLookup}>
6268
Search

src/pages/activity/global.tsx

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,54 @@
1-
import { Flex, Spinner, Text } from '@chakra-ui/react';
1+
import { Button, Flex, Spinner, Text } from '@chakra-ui/react';
22
import { UserRole } from '@prisma/client';
33
import { NextPage } from 'next';
4+
import { useState } from 'react';
45
import ActivityTable from '../../components/activity/ActivityTable';
56
import Layout from '../../components/layout/Layout';
7+
import { TicketWithNames } from '../../server/trpc/router/ticket';
68
import { trpc } from '../../utils/trpc';
79

810
/** All tickets made */
911
const GlobalActivityPage: NextPage = () => {
10-
const { data, isLoading } = trpc.ticket.getAllTickets.useQuery(undefined, { refetchOnWindowFocus: false });
12+
const [tickets, setTickets] = useState<TicketWithNames[]>([]);
13+
const [page, setPage] = useState(1);
14+
const { isLoading, refetch } = trpc.ticket.getAllTickets.useQuery(
15+
{ page },
16+
{
17+
refetchOnWindowFocus: false,
18+
onSuccess: data => {
19+
setTickets(old => [...old, ...data]);
20+
},
21+
},
22+
);
23+
24+
const handleLoadMore = async () => {
25+
setPage(old => old + 1);
26+
await refetch();
27+
};
1128

1229
return (
1330
<Layout restrictedTo={[UserRole.STAFF]}>
14-
<Flex ml={4} mt={4} flexDirection='column'>
31+
<Flex ml={4} mr={4} mt={4} flexDirection='column'>
1532
<Text fontSize='3xl' fontWeight='semibold'>
1633
Global Activity
1734
</Text>
18-
{isLoading && (
19-
<Flex flexDirection='column'>
20-
<Text>This will take a second...</Text>
21-
<Spinner />
22-
</Flex>
23-
)}
35+
<Text fontSize='lg'>
36+
This page shows all tickets made by students and staff. By default, 5 pages are shown. If you&lsquo;d like to
37+
load 5 more pages, click the button under the table. Note that a duration of -1 means that the ticket was
38+
never taken.
39+
</Text>
40+
{isLoading && <Spinner />}
2441
{!isLoading && (
25-
<ActivityTable tickets={data ?? []} title={`${data?.length ?? 0} tickets`} shouldShowCreatedBy={true} />
42+
<ActivityTable
43+
tickets={tickets}
44+
title={`${tickets.length} tickets`}
45+
shouldShowCreatedBy={true}
46+
shouldShowHelpedBy={true}
47+
/>
2648
)}
49+
<Button mt={2} colorScheme='yellow' onClick={handleLoadMore} disabled={isLoading}>
50+
Load more
51+
</Button>
2752
</Flex>
2853
</Layout>
2954
);

src/pages/activity/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ import { useSession } from 'next-auth/react';
33
import dynamic from 'next/dynamic';
44
import Layout from '../../components/layout/Layout';
55
import { UserRole } from '@prisma/client';
6-
import { Divider, Text } from '@chakra-ui/react';
6+
import { Divider } from '@chakra-ui/react';
77

88
/**
99
* Activity page which displays the activity log
1010
*/
1111
const ActivityPage: NextPage = () => {
12-
// const ActivityView = dynamic(() => import('../../components/activity/ActivityView'));
1312
const PersonalLog = dynamic(() => import('../../components/activity/PersonalLog'));
1413
const StatsView = dynamic(() => import('../../components/activity/StatsView'));
1514
const GlobalLog = dynamic(() => import('../../components/activity/GlobalLog'));

src/pages/api/trpc/[trpc].ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default createNextApiHandler({
99
router: appRouter,
1010
createContext,
1111
onError:
12-
env.NODE_ENV === 'development'
12+
env.NODE_ENV === "development"
1313
? ({ path, error }) => {
1414
console.error(`❌ tRPC failed on ${path}: ${error}`);
1515
}

src/server/trpc/router/ticket.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -695,13 +695,22 @@ export const ticketRouter = router({
695695
}),
696696

697697
/* For global log */
698-
getAllTickets: protectedStaffProcedure.query(async ({ ctx }) => {
699-
const tickets = await ctx.prisma.ticket.findMany({
700-
orderBy: { createdAt: 'desc' },
701-
});
698+
getAllTickets: protectedStaffProcedure
699+
.input(
700+
z.object({
701+
page: z.number(),
702+
}),
703+
)
704+
.query(async ({ input, ctx }) => {
705+
// With page size = 50
706+
const tickets = await ctx.prisma.ticket.findMany({
707+
skip: 50 * (input.page - 1),
708+
take: 50,
709+
orderBy: { createdAt: 'desc' },
710+
});
702711

703-
return convertTicketToTicketWithNames(tickets, ctx);
704-
}),
712+
return convertTicketToTicketWithNames(tickets, ctx);
713+
}),
705714

706715
getTicketsWithUserId: protectedProcedure
707716
.input(

src/utils/utils.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export const timeDifferenceInMinutes = (first: Date | null, second: Date | null)
2121
return Math.round(difference / 60000);
2222
};
2323

24-
export const getActivityTableColumns = (title: string, shouldShowCreatedBy: boolean) => {
25-
return [
24+
export const getActivityTableColumns = (title: string, shouldShowCreatedBy: boolean, shouldShowHelpedBy: boolean) => {
25+
const baseTable = [
2626
{
2727
Header: title,
2828
columns: [
@@ -42,15 +42,6 @@ export const getActivityTableColumns = (title: string, shouldShowCreatedBy: bool
4242
Header: 'Location',
4343
accessor: 'locationName',
4444
},
45-
shouldShowCreatedBy
46-
? {
47-
Header: 'Created by',
48-
accessor: 'createdByName',
49-
}
50-
: {
51-
Header: 'Helped by',
52-
accessor: 'helpedByName',
53-
},
5445
{
5546
Header: 'Duration (m)',
5647
accessor: 'duration',
@@ -62,6 +53,28 @@ export const getActivityTableColumns = (title: string, shouldShowCreatedBy: bool
6253
],
6354
},
6455
];
56+
57+
// This isn't necessary, but it keeps typescript happy
58+
if (baseTable[0] === undefined) {
59+
throw new Error('baseTable[0] is undefined');
60+
}
61+
62+
// Add createdBy and/or helpedBy columns
63+
if (shouldShowCreatedBy) {
64+
baseTable[0].columns.splice(4, 0, {
65+
Header: 'Created By',
66+
accessor: 'createdByName',
67+
});
68+
}
69+
70+
if (shouldShowHelpedBy) {
71+
baseTable[0].columns.splice(4, 0, {
72+
Header: 'Helped By',
73+
accessor: 'helpedByName',
74+
});
75+
}
76+
77+
return baseTable;
6578
};
6679

6780
export const addDurationToTickets = (tickets: TicketWithNames[]) => {
@@ -103,20 +116,20 @@ export type ImportUsersMethodPossiblitiesType = 'IMPORT_STAFF' | 'IMPORT_STAFF_A
103116

104117
export const resolveTime = (t: TicketStats) => {
105118
if (!t.resolvedAt || !t.createdAt) {
106-
return 0;
119+
return 0;
107120
}
108121
return Math.round(((t.resolvedAt.getTime() - t.createdAt.getTime()) / 60000) * 1000) / 1000; // in minutes, 3 decimals
109122
};
110123

111124
export const helpTime = (t: TicketStats) => {
112125
if (!t.resolvedAt || !t.helpedAt) {
113-
return 0;
126+
return 0;
114127
}
115128
return Math.round(((t.resolvedAt.getTime() - t.helpedAt.getTime()) / 60000) * 1000) / 1000; // in minutes, 3 decimals
116129
};
117130

118131
export const computeMean = (data: number[]) => {
119-
return data.length > 0 ? Math.round(data.reduce((a, b) => a + b) / data.length * 1000) / 1000 : 0;
132+
return data.length > 0 ? Math.round((data.reduce((a, b) => a + b) / data.length) * 1000) / 1000 : 0;
120133
};
121134

122135
export const computeMedian = (data: number[]) => {

0 commit comments

Comments
 (0)