diff --git a/components/admin/permit-holders/app-history/Card/AppHistoryRecord.tsx b/components/admin/permit-holders/app-history/Card/AppHistoryRecord.tsx index b67f4c14..d740ca8e 100644 --- a/components/admin/permit-holders/app-history/Card/AppHistoryRecord.tsx +++ b/components/admin/permit-holders/app-history/Card/AppHistoryRecord.tsx @@ -1,6 +1,6 @@ import { Button, Grid, GridItem, HStack, Text, VStack, Link as FileLink } from '@chakra-ui/react'; import PermitTypeBadge from '@components/admin/PermitTypeBadge'; -import { formatDate } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; import { getFileName } from '@lib/utils/s3-utils'; import { PermitRecord } from '@tools/admin/permit-holders/app-history'; import { titlecase } from '@tools/string'; @@ -40,7 +40,7 @@ const AppHistoryRecord: FC = ({ permit }) => { Request Type: {titlecase(type)} - Expiry date: {formatDate(expiryDate)} + Expiry date: {formatDateYYYYMMDD(expiryDate)} diff --git a/components/admin/permit-holders/current-application/Card/Header.tsx b/components/admin/permit-holders/current-application/Card/Header.tsx index 3e9a5983..811068e3 100644 --- a/components/admin/permit-holders/current-application/Card/Header.tsx +++ b/components/admin/permit-holders/current-application/Card/Header.tsx @@ -1,7 +1,7 @@ import { HStack, VStack, Text, Button } from '@chakra-ui/react'; import PermitTypeBadge from '@components/admin/PermitTypeBadge'; import RequestStatusBadge from '@components/admin/RequestStatusBadge'; -import { formatDate } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; import { CurrentApplication } from '@tools/admin/permit-holders/current-application'; import { titlecase } from '@tools/string'; import Link from 'next/link'; @@ -37,7 +37,7 @@ const Header: FC = ({ application }) => { Request Type: {titlecase(type)} - Expiry Date: {permitExpiryDate ? formatDate(permitExpiryDate) : 'N/A'} + Expiry Date: {permitExpiryDate ? formatDateYYYYMMDD(permitExpiryDate) : 'N/A'} diff --git a/components/admin/permit-holders/current-application/Card/MedicalInformationSection.tsx b/components/admin/permit-holders/current-application/Card/MedicalInformationSection.tsx index 0963dd4f..64a5cf89 100644 --- a/components/admin/permit-holders/current-application/Card/MedicalInformationSection.tsx +++ b/components/admin/permit-holders/current-application/Card/MedicalInformationSection.tsx @@ -1,5 +1,5 @@ import { Grid, GridItem, Text, List, ListItem, HStack, Badge } from '@chakra-ui/react'; -import { formatDate } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; import { MedicalInformationSectionData } from '@tools/admin/permit-holders/current-application'; import { titlecase } from '@tools/string'; import { FC } from 'react'; @@ -71,7 +71,7 @@ const MedicalInformationSection: FC = ({ medicalInformation }) => { - {!!disabilityCertificationDate && formatDate(disabilityCertificationDate)} + {!!disabilityCertificationDate && formatDateYYYYMMDD(disabilityCertificationDate)} {/* Mobility aids */} diff --git a/components/admin/permit-holders/medical-history/Modal.tsx b/components/admin/permit-holders/medical-history/Modal.tsx index 139648a0..70058f79 100644 --- a/components/admin/permit-holders/medical-history/Modal.tsx +++ b/components/admin/permit-holders/medical-history/Modal.tsx @@ -16,7 +16,7 @@ import { } from '@chakra-ui/react'; // Chakra UI import { ReactNode } from 'react'; // React import { MobilityAid } from '@lib/graphql/types'; // Application type & Aid enum -import { formatDate } from '@lib/utils/date'; // Date formatter util +import { formatDateYYYYMMDD } from '@lib/utils/date'; // Date formatter util import { MedicalHistoryRow } from '@tools/admin/permit-holders/medical-history'; import { titlecase } from '@tools/string'; @@ -62,7 +62,7 @@ export default function MedicalHistoryModal(props: MedicalHistoryModalProps) { paddingX="4px" > - {`${disability} (${formatDate(disabilityCertificationDate)})`} + {`${disability} (${formatDateYYYYMMDD(disabilityCertificationDate)})`} diff --git a/components/admin/requests/Header.tsx b/components/admin/requests/Header.tsx index d178d203..fd84c653 100644 --- a/components/admin/requests/Header.tsx +++ b/components/admin/requests/Header.tsx @@ -85,7 +85,8 @@ export default function RequestHeader({ - Received on {createdAt.toDateString()} at {createdAt.toLocaleTimeString('en-CA')} + Received on {formatDateYYYYMMDD(createdAt)} at{' '} + {createdAt.toLocaleTimeString('en-CA')} {displayShopifyUrl && ( diff --git a/components/admin/requests/create/SelectedPermitHolderCard.tsx b/components/admin/requests/create/SelectedPermitHolderCard.tsx index b98ce60c..38c3ce9f 100644 --- a/components/admin/requests/create/SelectedPermitHolderCard.tsx +++ b/components/admin/requests/create/SelectedPermitHolderCard.tsx @@ -15,7 +15,7 @@ import { Center, } from '@chakra-ui/react'; // Chakra UI import { formatFullName, formatPhoneNumber } from '@lib/utils/format'; // Date formatter util -import { formatDate } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; import { useQuery } from '@tools/hooks/graphql'; import { GetSelectedApplicantRequest, @@ -119,7 +119,7 @@ export default function SelectedPermitHolderCard(props: SelectedPermitHolderCard - Date of Birth: {formatDate(dateOfBirth)} + Date of Birth: {formatDateYYYYMMDD(dateOfBirth)} Gender: {gender.toLowerCase().replace(/^\w/, c => c.toUpperCase())} diff --git a/components/admin/requests/permit-holder-information/Card.tsx b/components/admin/requests/permit-holder-information/Card.tsx index 801a2837..2f0aee3a 100644 --- a/components/admin/requests/permit-holder-information/Card.tsx +++ b/components/admin/requests/permit-holder-information/Card.tsx @@ -18,7 +18,7 @@ import { } from '@tools/admin/requests/permit-holder-information'; // Applicant type import { getPermitExpiryStatus } from '@lib/utils/permit-expiry'; // Get variant of PermitHolderStatusBadge import { formatFullName, formatPhoneNumber } from '@lib/utils/format'; -import { formatDateYYYYMMDD, formatDateVerboseUTC } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; import PermitHolderStatusBadge from '@components/admin/PermitHolderStatusBadge'; import Updated from '@components/admin/Updated'; import Address from '@components/admin/Address'; @@ -224,7 +224,7 @@ const Card: FC = props => { {applicant && applicant.mostRecentPermit && ( // TODO: Fix text styles to avoid !important - Expiring {formatDateVerboseUTC(applicant.mostRecentPermit.expiryDate, true, true)} + Expiring {formatDateYYYYMMDD(applicant.mostRecentPermit.expiryDate)} )} diff --git a/components/admin/requests/processing/TaskStep.tsx b/components/admin/requests/processing/TaskStep.tsx index de3634ef..010007cd 100644 --- a/components/admin/requests/processing/TaskStep.tsx +++ b/components/admin/requests/processing/TaskStep.tsx @@ -1,7 +1,7 @@ import { Flex, VStack, Text, Box, Circle } from '@chakra-ui/react'; // Chakra UI import { CheckIcon } from '@chakra-ui/icons'; // Chakra UI icon import { ReactNode } from 'react'; // React -import { formatDateVerbose } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; type ProcessingTaskStepProps = { readonly id: number; @@ -56,7 +56,7 @@ export default function ProcessingTaskStep({ {_description} {showLog && !!log && ( - completed by {log.name} on {formatDateVerbose(log.date, true)} + completed by {log.name} on {formatDateYYYYMMDD(log.date)} )} diff --git a/components/admin/requests/reason-for-replacement/Card.tsx b/components/admin/requests/reason-for-replacement/Card.tsx index dff2aba7..766ba85e 100644 --- a/components/admin/requests/reason-for-replacement/Card.tsx +++ b/components/admin/requests/reason-for-replacement/Card.tsx @@ -3,7 +3,7 @@ import { Box, Text, SimpleGrid, Button } from '@chakra-ui/react'; // Chakra UI import PermitHolderInfoCard from '@components/admin/LayoutCard'; // Custom Card Component import EditReasonForReplacementModal from '@components/admin/requests/reason-for-replacement/EditModal'; // Edit modal import { reasonForReplacementFormSchema } from '@lib/applications/validation'; -import { formatDateVerbose } from '@lib/utils/date'; +import { formatDateYYYYMMDD } from '@lib/utils/date'; import { GetReasonForReplacementRequest, GetReasonForReplacementResponse, @@ -97,7 +97,7 @@ export default function ReasonForReplacementCard(props: ReplacementProps) { {titlecase(reason)} {lostTimestamp && ( - {formatDateVerbose(new Date(lostTimestamp))} + {formatDateYYYYMMDD(new Date(lostTimestamp), true)} )} {lostLocation && {lostLocation}} diff --git a/lib/applicants/resolvers.ts b/lib/applicants/resolvers.ts index 729e4944..3dc90543 100644 --- a/lib/applicants/resolvers.ts +++ b/lib/applicants/resolvers.ts @@ -162,6 +162,7 @@ export const applicants: Resolver< lte: expiryDateRangeTo?.toISOString(), }, }, + { active: true }, ], }, }; diff --git a/lib/invoices/utils.ts b/lib/invoices/utils.ts index ec52c77c..f6c9c0bd 100644 --- a/lib/invoices/utils.ts +++ b/lib/invoices/utils.ts @@ -2,7 +2,7 @@ import pdfPrinter from 'pdfmake'; import { Application, Prisma } from '@prisma/client'; import { Session } from 'next-auth'; import { formatFullName, formatPostalCode } from '@lib/utils/format'; -import { formatDate } from '@lib/utils/date'; // Date formatter util +import { formatDateYYYYMMDD } from '@lib/utils/date'; // Date formatter util import { PaymentType } from '@lib/graphql/types'; /** @@ -152,7 +152,7 @@ const pdfDefinition = (input: { [{ text: 'User No.:', alignment: 'right' }, userNumber || 'N/A'], [{ text: 'Permit Type:', alignment: 'right' }, permitType], [{ text: 'Receipt No.:', alignment: 'right' }, receiptNumber], - [{ text: 'Date Issued:', alignment: 'right' }, formatDate(dateIssued)], + [{ text: 'Date Issued:', alignment: 'right' }, formatDateYYYYMMDD(dateIssued)], [{ text: 'Issued By:', alignment: 'right' }, issuedBy], ], }, diff --git a/lib/reports/resolvers.ts b/lib/reports/resolvers.ts index 5207cd27..f7f945c0 100644 --- a/lib/reports/resolvers.ts +++ b/lib/reports/resolvers.ts @@ -10,9 +10,8 @@ import { PaymentType, } from '@lib/graphql/types'; import { SortOrder } from '@tools/types'; -import { formatAddress, formatFullName, formatPhoneNumber } from '@lib/utils/format'; // Formatting utils -import { formatDateTimeYYYYMMDDHHMMSS } from '@lib/utils/date'; // Formatting utils -import { formatDate } from '@lib/utils/date'; // Date formatter util +import { formatFullName, formatPhoneNumber, formatPostalCode } from '@lib/utils/format'; // Formatting utils +import { formatDateTimeYYYYMMDDHHMMSS, formatDateYYYYMMDD } from '@lib/utils/date'; // Formatting utils import { APPLICATIONS_COLUMNS, PERMIT_HOLDERS_COLUMNS } from '@tools/admin/reports'; import { Prisma } from '@prisma/client'; import { getSignedUrlForS3, serverUploadToS3 } from '@lib/utils/s3-utils'; @@ -100,12 +99,8 @@ export const generatePermitHoldersReport: Resolver< firstName, middleName, lastName, - dateOfBirth, - addressLine1, - addressLine2, - city, - province, postalCode, + dateOfBirth, guardian, permits, phone, @@ -115,30 +110,35 @@ export const generatePermitHoldersReport: Resolver< ...applicant, id, phone: formatPhoneNumber(phone), - dateOfBirth: formatDate(dateOfBirth), + dateOfBirth: formatDateYYYYMMDD(dateOfBirth), applicantName: formatFullName(firstName, middleName, lastName), + postalCode: formatPostalCode(postalCode), rcdPermitId: `#${permits[0].rcdPermitId}`, permitType: permits[0].type, - homeAddress: formatAddress(addressLine1, addressLine2, city, postalCode, province), guardianRelationship: guardian?.relationship, guardianPOAName: guardian && formatFullName(guardian.firstName, guardian.middleName, guardian.lastName), - guardianPOAAddress: - guardian && - formatAddress( - guardian.addressLine1, - guardian.addressLine2, - guardian.city, - guardian.postalCode, - guardian.province - ), + guardianAddressLine1: guardian && guardian.addressLine1, + guardianAddressLine2: guardian && guardian.addressLine2, + guardianCity: guardian && guardian.city, + guardianPostalCode: + guardian && guardian.postalCode && formatPostalCode(guardian.postalCode), + guardianProvince: guardian && guardian.province, }; } ); - const csvHeaders = PERMIT_HOLDERS_COLUMNS.filter(({ value }) => columnsSet.has(value)).map( - ({ name, reportColumnId }) => ({ id: reportColumnId, title: name }) - ); + const filteredColumns = PERMIT_HOLDERS_COLUMNS.filter(({ value }) => columnsSet.has(value)); + const csvHeaders: Array<{ id: string; title: string }> = []; + for (const { name, reportColumnId } of filteredColumns) { + if (typeof reportColumnId === 'string') { + csvHeaders.push({ id: reportColumnId, title: name }); + } else { + for (const [columnLabel, columnId] of reportColumnId) { + csvHeaders.push({ id: columnId, title: columnLabel }); + } + } + } // Generate CSV string from csv object. const csvStringifier = createObjectCsvStringifier({ @@ -263,15 +263,8 @@ export const generateApplicationsReport: Resolver< return { ...application, id: applicant?.id, - dateOfBirth: dateOfBirth && formatDate(dateOfBirth), - applicationDate: createdAt?.toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: '2-digit', - hour: '2-digit', - minute: 'numeric', - timeZone: 'America/Vancouver', - }), + dateOfBirth: dateOfBirth && formatDateYYYYMMDD(dateOfBirth), + applicationDate: createdAt ? formatDateYYYYMMDD(createdAt, true) : null, applicantName: formatFullName(firstName, middleName, lastName), processingFee: `$${processingFee}`, donationAmount: `$${donationAmount}`, diff --git a/lib/utils/date.ts b/lib/utils/date.ts index 0b5a866d..0b5c9f5e 100644 --- a/lib/utils/date.ts +++ b/lib/utils/date.ts @@ -14,10 +14,12 @@ export const formatDate = (date: Date, dateInput = false): string => { /** * Format date to be in YYYY-MM-DD format * @param {Date} date date to be formatted + * @param {boolean} withTime whether to include time in formatted date * @returns {string} formatted date */ -export const formatDateYYYYMMDD = (d: Date): string => { - return moment.utc(d).format('YYYY-MM-DD'); +export const formatDateYYYYMMDD = (d: Date, withTime = false): string => { + const formatString = withTime ? 'YYYY-MM-DD, hh:mm a' : 'YYYY-MM-DD'; + return moment.utc(d).format(formatString); }; /** diff --git a/pages/admin/index.tsx b/pages/admin/index.tsx index adebb505..dc801c5d 100644 --- a/pages/admin/index.tsx +++ b/pages/admin/index.tsx @@ -42,7 +42,7 @@ import { ApplicationStatus, ApplicationType, PermitType } from '@lib/graphql/typ import useDebounce from '@tools/hooks/useDebounce'; // Debounce hook import { Column } from 'react-table'; import { formatFullName } from '@lib/utils/format'; // String formatter util -import { formatDateVerbose } from '@lib/utils/date'; // Date Formatter Util +import { formatDateYYYYMMDD } from '@lib/utils/date'; // Date Formatter Util import GenerateReportModal from '@components/admin/requests/reports/GenerateModal'; // Generate report modal import EmptyMessage from '@components/EmptyMessage'; @@ -82,7 +82,7 @@ const COLUMNS: Column[] = [ width: 240, sortDescFirst: true, Cell: ({ value }) => { - return {formatDateVerbose(value)}; + return {formatDateYYYYMMDD(value, true)}; }, }, { diff --git a/pages/admin/permit-holders.tsx b/pages/admin/permit-holders.tsx index 763558c7..d1a238dc 100644 --- a/pages/admin/permit-holders.tsx +++ b/pages/admin/permit-holders.tsx @@ -46,7 +46,7 @@ import { Column } from 'react-table'; // Column type for table import useDebounce from '@tools/hooks/useDebounce'; // Debouncer import { useEffect } from 'react'; // React import { formatFullName, formatPhoneNumber } from '@lib/utils/format'; // String formatter util -import { formatDate } from '@lib/utils/date'; // Date formatter util +import { formatDateYYYYMMDD } from '@lib/utils/date'; // Date formatter util import SetPermitHolderToInactiveModal from '@components/admin/permit-holders/table/ConfirmSetInactiveModal'; // Set Permit Holder To Inactive modal import SetPermitHolderToActiveModal from '@components/admin/permit-holders/table/ConfirmSetActiveModal'; // Set Permit Holder To Active modal import GenerateReportModal from '@components/admin/permit-holders/reports/GenerateModal'; // Generate report modal @@ -192,7 +192,7 @@ const PermitHolders: NextPage = () => { accessor: 'dateOfBirth', disableSortBy: true, Cell: ({ value }) => { - return {formatDate(value)}; + return {formatDateYYYYMMDD(value)}; }, }, { diff --git a/tools/admin/reports.ts b/tools/admin/reports.ts index 25f6d148..fa2e685c 100644 --- a/tools/admin/reports.ts +++ b/tools/admin/reports.ts @@ -65,7 +65,7 @@ export const APPLICATIONS_COLUMNS: Array<{ export const PERMIT_HOLDERS_COLUMNS: Array<{ name: string; value: PermitHoldersReportColumn; - reportColumnId: string; + reportColumnId: string | Array<[string, string]>; }> = [ { name: 'User ID', @@ -85,7 +85,13 @@ export const PERMIT_HOLDERS_COLUMNS: Array<{ { name: 'Home Address', value: 'HOME_ADDRESS', - reportColumnId: 'homeAddress', + reportColumnId: [ + ['Address Line 1', 'addressLine1'], + ['Address Line 2', 'addressLine2'], + ['City', 'city'], + ['Province', 'province'], + ['Postal Code', 'postalCode'], + ], }, { name: 'Email', @@ -110,7 +116,13 @@ export const PERMIT_HOLDERS_COLUMNS: Array<{ { name: 'Guardian/POA Address', value: 'GUARDIAN_POA_ADDRESS', - reportColumnId: 'guardianPOAAddress', + reportColumnId: [ + ['Guardian/POA Address Line 1', 'guardianAddressLine1'], + ['Guardian/POA Address Line 2', 'guardianAddressLine2'], + ['Guardian/POA City', 'guardianCity'], + ['Guardian/POA Province', 'guardianProvince'], + ['Guardian/POA Postal Code', 'guardianPostalCode'], + ], }, { name: 'Recent APP Number',