Skip to content

Commit 92a56e3

Browse files
sherryhlijennchennkj3moraesChinemeremChigboBraydenRoyston
authored
[Release] Version 0.3.5 (#384)
* [enhancement] Track application status to return to original tab in admin view (#372) * Track application status to return to correct tab * fixup! Track application status to return to correct tab * [Fix] Unsaved Doctor's Information (#374) * used values.doctorInformation instead of doctorInformation * using validated values for doctor's info * [Improvement] Add pagination controls to top of requests/permit holders tables (#376) * Add pagination to top of requests table * Add pagination to top of permit holders table * Add Vihaan to employees.ts (#379) * Add Braydent to employee.ts (#380) * broyston: updated stamp png to contain new address (#382) * Add phone number and addresses to request report (#383) * Remove applicant deletion (#377) --------- Co-authored-by: Jennifer Chen <32009013+jennchenn@users.noreply.github.com> Co-authored-by: Keane Moraes <lordvader3002@gmail.com> Co-authored-by: Chinemerem <chinemeremchigbo@Outlook.com> Co-authored-by: Brayden Royston <brayden.royston10@gmail.com>
1 parent a645238 commit 92a56e3

File tree

13 files changed

+223
-86
lines changed

13 files changed

+223
-86
lines changed

components/admin/permit-holders/Header.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import { ChevronDownIcon, ChevronLeftIcon } from '@chakra-ui/icons'; // Chakra UI icon
1919
import Link from 'next/link'; // Link
2020
import { ApplicantStatus } from '@lib/graphql/types';
21+
import { CurrentApplication } from '@tools/admin/permit-holders/current-application';
2122
import PermitHolderStatusBadge from '@components/admin/PermitHolderStatusBadge';
2223
import ConfirmDeleteApplicantModal from '@components/admin/permit-holders/table/ConfirmDeleteApplicantModal';
2324
import SetPermitHolderToInactiveModal from '@components/admin/permit-holders/table/ConfirmSetInactiveModal';
@@ -31,12 +32,13 @@ type PermitHolderHeaderProps = {
3132
status: ApplicantStatus;
3233
inactiveReason?: string;
3334
notes: string;
35+
mostRecentApplication: CurrentApplication | null;
3436
};
3537
readonly refetch: () => void;
3638
};
3739

3840
export default function PermitHolderHeader({
39-
applicant: { id, name, status, inactiveReason, notes },
41+
applicant: { id, name, status, inactiveReason, notes, mostRecentApplication },
4042
refetch,
4143
}: PermitHolderHeaderProps) {
4244
const router = useRouter();
@@ -108,13 +110,15 @@ export default function PermitHolderHeader({
108110
>
109111
{`Set as ${status === 'ACTIVE' ? 'Inactive' : 'Active'}`}
110112
</MenuItem>
111-
<MenuItem
112-
color="text.critical"
113-
textStyle="button-regular"
114-
onClick={onOpenDeleteApplicantModal}
115-
>
116-
{'Delete Permit Holder'}
117-
</MenuItem>
113+
{mostRecentApplication?.processing?.status == 'COMPLETED' ? null : (
114+
<MenuItem
115+
color="text.critical"
116+
textStyle="button-regular"
117+
onClick={onOpenDeleteApplicantModal}
118+
>
119+
{'Delete Permit Holder'}
120+
</MenuItem>
121+
)}
118122
</MenuList>
119123
</Menu>
120124
</Box>

components/admin/requests/Header.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { ApplicationStatus, ApplicationType, PermitType } from '@lib/graphql/typ
2525
import { titlecase } from '@tools/string';
2626
import { formatDateYYYYMMDD, formatDateYYYYMMDDLocal } from '@lib/utils/date';
2727
import { getPermanentPermitExpiryDate } from '@lib/utils/permit-expiry';
28+
import { useEffect, useState } from 'react'; // React
2829

2930
type RequestHeaderProps = {
3031
readonly id: number;
@@ -87,6 +88,22 @@ export default function RequestHeader({
8788

8889
const router = useRouter();
8990

91+
const [backLink, setBackLink] = useState('/admin');
92+
const generateBackLink = () => {
93+
let status;
94+
const routerQuery = router.query;
95+
if (routerQuery === undefined || routerQuery.origin === undefined) {
96+
status = applicationStatus;
97+
} else {
98+
status = routerQuery.origin;
99+
}
100+
setBackLink(`/admin?tab=${status}`);
101+
};
102+
103+
useEffect(() => {
104+
generateBackLink();
105+
}, []);
106+
90107
// Delete application modal state
91108
const {
92109
isOpen: isDeleteApplicationModalOpen,
@@ -96,12 +113,13 @@ export default function RequestHeader({
96113

97114
return (
98115
<Box textAlign="left">
99-
<NextLink href="/admin" passHref>
116+
<NextLink href={backLink} passHref>
100117
<Text textStyle="button-semibold" textColor="primary" as="a">
101118
<ChevronLeftIcon />
102119
All requests
103120
</Text>
104121
</NextLink>
122+
105123
<VStack alignItems="stretch">
106124
<Flex marginTop={5} alignItems="baseline" justifyContent="space-between">
107125
<Box>

lib/graphql/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ export type ApplicationsReportColumn =
178178
| 'APPLICANT_NAME'
179179
| 'APPLICANT_DATE_OF_BIRTH'
180180
| 'APP_NUMBER'
181+
| 'PHONE_NUMBER'
182+
| 'HOME_ADDRESS'
181183
| 'APPLICATION_DATE'
182184
| 'PAYMENT_METHOD'
183185
| 'FEE_AMOUNT'

lib/reports/resolvers.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ export const generateApplicationsReport: Resolver<
223223
firstName: true,
224224
middleName: true,
225225
lastName: true,
226+
addressLine1: true,
227+
addressLine2: true,
228+
city: true,
229+
province: true,
230+
postalCode: true,
231+
phone: true,
226232
type: true,
227233
createdAt: true,
228234
paymentMethod: true,
@@ -262,6 +268,10 @@ export const generateApplicationsReport: Resolver<
262268
firstName,
263269
middleName,
264270
lastName,
271+
phone,
272+
addressLine1,
273+
addressLine2,
274+
postalCode,
265275
type,
266276
createdAt,
267277
processingFee,
@@ -292,6 +302,9 @@ export const generateApplicationsReport: Resolver<
292302
id: applicant?.id,
293303
applicantName: formatFullName(firstName, middleName, lastName),
294304
dateOfBirth: dateOfBirth && formatDateYYYYMMDD(dateOfBirth),
305+
address: formatStreetAddress(addressLine1, addressLine2),
306+
postalCode: formatPostalCode(postalCode),
307+
phone: formatPhoneNumber(phone),
295308
rcdPermitId: permit?.rcdPermitId ? `#${permit.rcdPermitId}` : null,
296309
applicationDate: createdAt ? formatDateYYYYMMDDLocal(createdAt, true) : null,
297310
processingFee: `$${processingFee}`,
@@ -314,9 +327,17 @@ export const generateApplicationsReport: Resolver<
314327
}
315328
);
316329

317-
const csvHeaders = APPLICATIONS_COLUMNS.filter(({ value }) => columnsSet.has(value)).map(
318-
({ name, reportColumnId }) => ({ id: reportColumnId, title: name })
319-
);
330+
const filteredColumns = APPLICATIONS_COLUMNS.filter(({ value }) => columnsSet.has(value));
331+
const csvHeaders: Array<{ id: string; title: string }> = [];
332+
for (const { name, reportColumnId } of filteredColumns) {
333+
if (typeof reportColumnId === 'string') {
334+
csvHeaders.push({ id: reportColumnId, title: name });
335+
} else {
336+
for (const [columnLabel, columnId] of reportColumnId) {
337+
csvHeaders.push({ id: columnId, title: columnLabel });
338+
}
339+
}
340+
}
320341

321342
// Generate CSV string from csv object.
322343
const csvStringifier = createObjectCsvStringifier({

lib/reports/schema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export default gql`
2525
APPLICANT_NAME
2626
APPLICANT_DATE_OF_BIRTH
2727
APP_NUMBER
28+
PHONE_NUMBER
29+
HOME_ADDRESS
2830
APPLICATION_DATE
2931
PAYMENT_METHOD
3032
FEE_AMOUNT

pages/admin/index.tsx

Lines changed: 82 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,39 @@ import { formatFullName } from '@lib/utils/format'; // String formatter util
4444
import { formatDateYYYYMMDDLocal } from '@lib/utils/date'; // Date Formatter Util
4545
import EmptyMessage from '@components/EmptyMessage';
4646

47+
interface RouterQuery {
48+
tab?: string;
49+
}
50+
51+
export const getTabIndex = (routerQuery: RouterQuery): number => {
52+
if (routerQuery === undefined || routerQuery.tab === undefined) {
53+
return 1;
54+
}
55+
const tabName = routerQuery.tab;
56+
switch (tabName) {
57+
case 'ALL':
58+
return 0;
59+
case 'PENDING':
60+
return 1;
61+
case 'IN_PROGRESS':
62+
return 2;
63+
case 'COMPLETED':
64+
return 3;
65+
case 'REJECTED':
66+
return 4;
67+
default:
68+
return 1;
69+
}
70+
};
71+
72+
const tabIndexToStatus: { [key: number]: ApplicationStatus | 'ALL' } = {
73+
0: 'ALL',
74+
1: 'PENDING',
75+
2: 'IN_PROGRESS',
76+
3: 'COMPLETED',
77+
4: 'REJECTED',
78+
};
79+
4780
// Placeholder columns
4881
const COLUMNS: Column<ApplicationRow>[] = [
4982
{
@@ -126,6 +159,7 @@ const PAGE_SIZE = 20;
126159
const Requests: NextPage = () => {
127160
// Router
128161
const router = useRouter();
162+
const routerQuery: RouterQuery = router.query;
129163

130164
// Filters
131165
const [statusFilter, setStatusFilter] = useState<ApplicationStatus | null>('PENDING');
@@ -145,6 +179,20 @@ const Requests: NextPage = () => {
145179
const [pageNumber, setPageNumber] = useState(0);
146180
const [recordsCount, setRecordsCount] = useState(0);
147181

182+
// Tabs
183+
const [tabIndex, setTabIndex] = useState(0);
184+
const getTabFromRoute = (): number => {
185+
const index = getTabIndex(routerQuery);
186+
setTabIndex(index);
187+
return index;
188+
};
189+
190+
const handleTabChange = () => {
191+
const status = tabIndexToStatus[tabIndex];
192+
setStatusFilter(status === 'ALL' ? null : status);
193+
router.push({ query: { tab: status } });
194+
};
195+
148196
// Make query to applications resolver
149197
const { refetch, loading } = useQuery<GetApplicationsResponse, GetApplicationsRequest>(
150198
GET_APPLICATIONS_QUERY,
@@ -191,6 +239,16 @@ const Requests: NextPage = () => {
191239
}
192240
);
193241

242+
// Determine the active tab on page load based on the route
243+
useEffect(() => {
244+
getTabFromRoute();
245+
}, []);
246+
247+
useEffect(() => {
248+
if (tabIndex === null) return;
249+
handleTabChange();
250+
}, [tabIndex]);
251+
194252
// Set page number to 0 after every filter or sort change
195253
useEffect(() => {
196254
setPageNumber(0);
@@ -228,48 +286,19 @@ const Requests: NextPage = () => {
228286
</HStack>
229287
</Flex>
230288
<Box border="1px solid" borderColor="border.secondary" borderRadius="12px" bgColor="white">
231-
<Tabs marginBottom="20px" defaultIndex={1}>
232-
<TabList paddingX="24px">
233-
<Tab
234-
height="64px"
235-
onClick={() => {
236-
setStatusFilter(null);
237-
}}
238-
>
239-
All
240-
</Tab>
241-
<Tab
242-
height="64px"
243-
onClick={() => {
244-
setStatusFilter('PENDING');
245-
}}
246-
>
247-
Pending
248-
</Tab>
249-
<Tab
250-
height="64px"
251-
onClick={() => {
252-
setStatusFilter('IN_PROGRESS');
253-
}}
254-
>
255-
In Progress
256-
</Tab>
257-
<Tab
258-
height="64px"
259-
onClick={() => {
260-
setStatusFilter('COMPLETED');
261-
}}
262-
>
263-
Completed
264-
</Tab>
265-
<Tab
266-
height="64px"
267-
onClick={() => {
268-
setStatusFilter('REJECTED');
269-
}}
270-
>
271-
Rejected
272-
</Tab>
289+
<Tabs
290+
marginBottom="20px"
291+
index={tabIndex}
292+
onChange={index => {
293+
setTabIndex(index);
294+
}}
295+
>
296+
<TabList paddingX="24px" defaultIndex={1}>
297+
<Tab height="64px">All</Tab>
298+
<Tab height="64px">Pending</Tab>
299+
<Tab height="64px">In Progress</Tab>
300+
<Tab height="64px">Completed</Tab>
301+
<Tab height="64px">Rejected</Tab>
273302
</TabList>
274303
</Tabs>
275304
<Box padding="0 24px">
@@ -379,13 +408,23 @@ const Requests: NextPage = () => {
379408
</Flex>
380409
{requestsData.length > 0 ? (
381410
<>
411+
<Flex justifyContent="flex-end">
412+
<Pagination
413+
pageNumber={pageNumber}
414+
pageSize={PAGE_SIZE}
415+
totalCount={recordsCount}
416+
onPageChange={setPageNumber}
417+
/>
418+
</Flex>
382419
<Table
383420
columns={COLUMNS}
384421
data={requestsData}
385422
loading={loading}
386423
initialSort={sortOrder}
387424
onChangeSortOrder={setSortOrder}
388-
onRowClick={({ id }) => router.push(`/admin/request/${id}`)}
425+
onRowClick={({ id }) =>
426+
router.push(`/admin/request/${id}?origin=${tabIndexToStatus[tabIndex]}`)
427+
}
389428
/>
390429
<Flex justifyContent="flex-end">
391430
<Pagination

pages/admin/permit-holder/[id].tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default function PermitHolder({ id: idString }: Props) {
5959
status,
6060
inactiveReason: inactiveReason || undefined,
6161
notes: notes || '',
62+
mostRecentApplication: currentApplication,
6263
}}
6364
refetch={refetch}
6465
/>

0 commit comments

Comments
 (0)