diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c85de077..9aa26b90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-20.04] node: [14.17.0] steps: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f45dd4ae --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,91 @@ +# Contributions + +## New Contributors + +Thank you for taking the time to contribute to this repo! This project is actively in use with our +clients and requires the help of volunteers like yourself to maintain and continue to foster this +project’s growth. Every contribution helps and credit is always given! + +To get started contributing to this project, please email . An exec on the team will +send you a Slack invite and will onboard you onto our project. + +# Roles + +We have two roles on the maintenance team: Blueprint Software Foundation (BSF) executive and +contributors. + +## Blueprint Software Foundation executive member + +BSF is an overarching organization responsible for the upkeep of projects shipped by UW Blueprint. +As of writing, BSF is composed of 3 executives: 2 alumni and a UW Blueprint president. + +Executives are responsible for maintaining communications with clients and with UW Blueprint +regarding maintenance projects and onboarding new projects onto BSF. They are also responsible for +coordinating work on tasks/issues and onboarding contributors. + +## Contributors + +Much of the fruitful maintenance and upkeep work on projects will be due to our wonderful +contributors! Contributors will work with execs in prioritizing and planning maintenance work and +shipping the work to our clients. As of writing, **contributors will be sourced from UW Blueprint +alumni** but we are planning on opening up contributions to those not part of UW Blueprint. + +# Contribution workflow + +Please follow the following steps in order to productively contribute to this repository. + +## Step 1: Fork the repo + +On the repository’s main page, click ‘Fork Repo’ at the top of the page. + +## Step 2: Configure your environment + +Once you have Notion access, take a look at the README.md file, +[development guidelines](https://www.notion.so/uwblueprintexecs/Development-processes-a0313f2bef9941fc8752c8e7b5be5e70) +and +[engineering best practices](https://www.notion.so/uwblueprintexecs/READ-Best-Practices-Engineering-3174edea363b4d4896af8dfc461cfd9c) +to set up your environment. + +## Step 3: Connect with people + +As mentioned above, if you are not already on our Slack, please email . Once added, +please talk to the execs on which issues or features are highest priority. This will be available as +a Notion board as well. + +Once an issue is chosen, discuss with fellow contributors and execs on Slack on how you plan on +approaching the issues. We will subsequently assign you the issue and you can get cracking! + +## Step 4: Prepare PR + +Clone your fork locally and start to make your changes. Small changes are always greater than huge, +breaking changes! Make sure that you test a variety of situations before you push your change to +your fork! + +## Step 5: Pass PR review + +Once you feel confident that your change addresses the issue/feature spec, sync your fork with the +main repository and open up a PR on the main repo from your fork. Please provide a detailed +description of your change and ask for the reviews of an exec/designated contributor. + +Please be cognizant of an executive’s relatively limited time. Reviews may take longer than you +would expect! Use Slack wisely to ensure that you can get a review in a timely manner. + +# Thank you! + +We want to thank the following individuals for their tireless contributions: + +- Oustan Ding +- Carelynn Tsai +- Vedant Patel +- Angela Dietz +- Anish Aggarwal +- Christian Chan +- Emilio Mena +- Jihad Bunkheila +- Bonnie Chin +- Anthea Tawiah +- Charmaine Wang +- Jeffrey Zhang +- Amanda Guo +- Andy Lee +- Jennifer Tsai diff --git a/README.md b/README.md index be134145..71f42824 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,40 @@ applicant-facing application portal and an internal user/APP management portal. ## Run locally +1. Start database + +```bash +docker-compose up --build +``` + +2. Run the application + +```bash +yarn install +npx prisma generate +yarn dev +``` + +3. Deploy prisma schema + +```bash +npx prisma db push +``` + +4. Seed database + +```bash +npx prisma db seed --preview-feature +``` + +5. Verify database + +```bash +docker exec -it rcd_db /bin/bash -c "psql -U postgres -d rcd" +``` + +## Run locally (Heroku) + Duplicate `.env.sample` to `.env` and configure environment variables. To deploy your database schema, run: diff --git a/components/admin/permit-holders/Header.tsx b/components/admin/permit-holders/Header.tsx index 4e5e9c18..33b93ad3 100644 --- a/components/admin/permit-holders/Header.tsx +++ b/components/admin/permit-holders/Header.tsx @@ -9,6 +9,7 @@ import { MenuItem, MenuList, Text, + Spacer, useDisclosure, VStack, Wrap, @@ -71,30 +72,42 @@ export default function PermitHolderHeader({ - - ID: #{id} - - - } - height="30px" - bg="background.gray" - _hover={{ bg: 'background.grayHover' }} - color="black" - > - More Actions - - - + + ID: #{id} + + + + + } + height="30px" + bg="background.gray" + _hover={{ bg: 'background.grayHover' }} + color="black" > - {`Set as ${status === 'ACTIVE' ? 'Inactive' : 'Active'}`} - - - + More Actions + + + + {`Set as ${status === 'ACTIVE' ? 'Inactive' : 'Active'}`} + + + + + + {notes && ( + + Note: {notes} + + )} + + diff --git a/components/admin/requests/Header.tsx b/components/admin/requests/Header.tsx index fd84c653..e823f8ba 100644 --- a/components/admin/requests/Header.tsx +++ b/components/admin/requests/Header.tsx @@ -6,7 +6,7 @@ import ShopifyBadge from '@components/admin/ShopifyBadge'; import PermitTypeBadge from '@components/admin/PermitTypeBadge'; import { ApplicationStatus, ApplicationType, PermitType } from '@lib/graphql/types'; import { titlecase } from '@tools/string'; -import { formatDateYYYYMMDD } from '@lib/utils/date'; +import { formatDateYYYYMMDD, formatDateYYYYMMDDLocal } from '@lib/utils/date'; import { getPermanentPermitExpiryDate } from '@lib/utils/permit-expiry'; type RequestHeaderProps = { @@ -85,7 +85,7 @@ export default function RequestHeader({ - Received on {formatDateYYYYMMDD(createdAt)} at{' '} + Received on {formatDateYYYYMMDDLocal(createdAt)} at{' '} {createdAt.toLocaleTimeString('en-CA')} diff --git a/components/admin/requests/payment-information/Card.tsx b/components/admin/requests/payment-information/Card.tsx index 1c774dc0..c6337956 100644 --- a/components/admin/requests/payment-information/Card.tsx +++ b/components/admin/requests/payment-information/Card.tsx @@ -100,6 +100,7 @@ const Card: FC = props => { paymentInformation={{ paymentMethod, donationAmount, + processingFee, shippingAddressSameAsHomeAddress, shippingFullName, shippingAddressLine1, @@ -135,7 +136,7 @@ const Card: FC = props => { - Permit Fee (fixed) + Permit Fee diff --git a/components/admin/requests/payment-information/Form.tsx b/components/admin/requests/payment-information/Form.tsx index b77f20d1..8956af05 100644 --- a/components/admin/requests/payment-information/Form.tsx +++ b/components/admin/requests/payment-information/Form.tsx @@ -1,19 +1,5 @@ import { PaymentInformationFormData } from '@tools/admin/requests/payment-information'; -import { - FormControl, - FormLabel, - Input, - Text, - Stack, - FormHelperText, - Radio, - Box, - InputGroup, - InputLeftElement, - Grid, - GridItem, - Divider, -} from '@chakra-ui/react'; // Chakra UI +import { Text, Stack, FormHelperText, Radio, Box, Grid, GridItem, Divider } from '@chakra-ui/react'; // Chakra UI import { PaymentType } from '@lib/graphql/types'; import TextField from '@components/form/TextField'; import RadioGroupField from '@components/form/RadioGroupField'; @@ -52,20 +38,7 @@ export default function PaymentDetailsForm({ paymentInformation }: PaymentDetail - - - {'Permit fee '} - - {'(fixed cost)'} - - - - - {'$'} - - - - + diff --git a/components/admin/requests/reason-for-replacement/Card.tsx b/components/admin/requests/reason-for-replacement/Card.tsx index 766ba85e..d87592d2 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 { formatDateYYYYMMDD } from '@lib/utils/date'; +import { formatDateYYYYMMDDLocal } from '@lib/utils/date'; import { GetReasonForReplacementRequest, GetReasonForReplacementResponse, @@ -97,7 +97,7 @@ export default function ReasonForReplacementCard(props: ReplacementProps) { {titlecase(reason)} {lostTimestamp && ( - {formatDateYYYYMMDD(new Date(lostTimestamp), true)} + {formatDateYYYYMMDDLocal(new Date(lostTimestamp), true)} )} {lostLocation && {lostLocation}} diff --git a/components/applicant/renewals/IdentityVerification.tsx b/components/applicant/renewals/IdentityVerification.tsx index aacb4f37..bc3202c2 100644 --- a/components/applicant/renewals/IdentityVerification.tsx +++ b/components/applicant/renewals/IdentityVerification.tsx @@ -146,7 +146,7 @@ const IdentityVerification: FC = () => { - {`You can find your user ID on the back of your wallet card. If you cannot find your + {`You can find your user ID on the back of your wallet card as well as on the renewal notice. If you cannot find your wallet card, please call RCD at 604-232-2404.`} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..6401c86a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: "3.7" + +services: + db: + container_name: rcd_db + image: postgres:12-alpine + ports: + - 5432:5432 + volumes: + - postgres_data:/var/lib/postgresql/data/ + env_file: + - ./.env + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + postgres_data: diff --git a/lib/applications/resolvers.ts b/lib/applications/resolvers.ts index db514ddc..c132101e 100644 --- a/lib/applications/resolvers.ts +++ b/lib/applications/resolvers.ts @@ -336,6 +336,7 @@ export const createNewApplication: Resolver< const paymentInformation = { paymentMethod: input.paymentMethod, + processingFee: input.processingFee, donationAmount, shippingAddressSameAsHomeAddress: input.shippingAddressSameAsHomeAddress, shippingFullName: input.shippingFullName, @@ -382,7 +383,6 @@ export const createNewApplication: Resolver< application = await prisma.application.create({ data: { type: 'NEW', - processingFee: process.env.PROCESSING_FEE, donationAmount: donationAmount || 0, // Connect to applicant if applicant exists in DB ...(applicantId && { @@ -557,8 +557,11 @@ export const createRenewalApplication: Resolver< otherRequiresWiderParkingSpaceReason, }; + const { processingFee } = input; + const paymentInformation = { paymentMethod, + processingFee, donationAmount, shippingAddressSameAsHomeAddress, shippingFullName, @@ -606,7 +609,6 @@ export const createRenewalApplication: Resolver< createdRenewalApplication = await prisma.application.create({ data: { type: 'RENEWAL', - processingFee: process.env.PROCESSING_FEE, donationAmount: donationAmount || 0, phone: stripPhoneNumber(phone), ...data, @@ -965,8 +967,12 @@ export const createReplacementApplication: Resolver< city, postalCode, }; + + const { processingFee } = input; + const paymentInformation = { paymentMethod, + processingFee, donationAmount, shippingAddressSameAsHomeAddress, shippingFullName, @@ -1034,7 +1040,6 @@ export const createReplacementApplication: Resolver< application = await prisma.application.create({ data: { type: 'REPLACEMENT', - processingFee: process.env.PROCESSING_FEE, donationAmount: donationAmount || 0, phone: stripPhoneNumber(phone), postalCode: stripPostalCode(postalCode), diff --git a/lib/applications/schema.ts b/lib/applications/schema.ts index 869343d9..0f525bd6 100644 --- a/lib/applications/schema.ts +++ b/lib/applications/schema.ts @@ -386,8 +386,9 @@ export default gql` requiresWiderParkingSpaceReason: RequiresWiderParkingSpaceReason otherRequiresWiderParkingSpaceReason: String - # Payment information (omit processing fee) + # Payment information paymentMethod: PaymentType! + processingFee: String! # Input monetary value as string donationAmount: String # Input monetary value as string # Shipping information shippingAddressSameAsHomeAddress: Boolean! @@ -454,6 +455,7 @@ export default gql` # Payment information paymentMethod: PaymentType! + processingFee: String # Input monetary value as string donationAmount: String # Input monetary value as string # Shipping information shippingAddressSameAsHomeAddress: Boolean! @@ -555,9 +557,9 @@ export default gql` stolenPoliceOfficerName: String eventDescription: String - # Payment information (omit processing fee) paymentMethod: PaymentType! # Input monetary value as string + processingFee: String! donationAmount: String # Shipping information @@ -722,8 +724,9 @@ export default gql` # Application ID id: Int! - # Payment information (omit processing fee) + # Payment information paymentMethod: PaymentType! + processingFee: String! donationAmount: String # Shipping information diff --git a/lib/applications/validation.ts b/lib/applications/validation.ts index 0871de1e..f8634ced 100644 --- a/lib/applications/validation.ts +++ b/lib/applications/validation.ts @@ -13,7 +13,7 @@ import { AccessibleConvertedVanLoadingMethod, RequiresWiderParkingSpaceReason, } from '@lib/graphql/types'; -import { phoneNumberRegex, postalCodeRegex } from '@lib/utils/validation'; +import { monetaryValueRegex, phoneNumberRegex, postalCodeRegex } from '@lib/utils/validation'; /** * Additional Questions form validation schema @@ -75,9 +75,12 @@ export const paymentInformationSchema = object({ .oneOf(Object.values(PaymentType)) .required('Please select a payment method'), donationAmount: string() - .matches(/^([0-9]+\.?[0-9]{0,2}|\.[0-9]{1,2}|)$/, 'Please enter a valid amount') + .matches(monetaryValueRegex, 'Please enter a valid amount') .nullable() .default(null), + processingFee: string() + .matches(monetaryValueRegex, 'Please enter a valid amount') + .required('Please enter a permit fee'), shippingAddressSameAsHomeAddress: bool().default(false), shippingFullName: string() .nullable() diff --git a/lib/graphql/types.ts b/lib/graphql/types.ts index 1781fb31..4404b578 100644 --- a/lib/graphql/types.ts +++ b/lib/graphql/types.ts @@ -321,6 +321,7 @@ export type CreateNewApplicationInput = { requiresWiderParkingSpaceReason: Maybe; otherRequiresWiderParkingSpaceReason: Maybe; paymentMethod: PaymentType; + processingFee: Scalars['String']; donationAmount: Maybe; shippingAddressSameAsHomeAddress: Scalars['Boolean']; shippingFullName: Maybe; @@ -373,6 +374,7 @@ export type CreateRenewalApplicationInput = { requiresWiderParkingSpaceReason: Maybe; otherRequiresWiderParkingSpaceReason: Maybe; paymentMethod: PaymentType; + processingFee: Scalars['String']; donationAmount: Maybe; shippingAddressSameAsHomeAddress: Scalars['Boolean']; shippingFullName: Maybe; @@ -418,6 +420,7 @@ export type CreateReplacementApplicationInput = { stolenPoliceOfficerName: Maybe; eventDescription: Maybe; paymentMethod: PaymentType; + processingFee: Scalars['String']; donationAmount: Maybe; shippingAddressSameAsHomeAddress: Scalars['Boolean']; shippingFullName: Maybe; @@ -1317,6 +1320,7 @@ export type UpdateApplicationGuardianInformationResult = { export type UpdateApplicationPaymentInformationInput = { id: Scalars['Int']; paymentMethod: PaymentType; + processingFee: Scalars['String']; donationAmount: Maybe; shippingAddressSameAsHomeAddress: Scalars['Boolean']; shippingFullName: Maybe; diff --git a/lib/reports/resolvers.ts b/lib/reports/resolvers.ts index 36b9b612..1ab1bb13 100644 --- a/lib/reports/resolvers.ts +++ b/lib/reports/resolvers.ts @@ -11,7 +11,11 @@ import { } from '@lib/graphql/types'; import { SortOrder } from '@tools/types'; import { formatFullName, formatPhoneNumber, formatPostalCode } from '@lib/utils/format'; // Formatting utils -import { formatDateTimeYYYYMMDDHHMMSS, formatDateYYYYMMDD } from '@lib/utils/date'; // Formatting utils +import { + formatDateTimeYYYYMMDDHHMMSS, + formatDateYYYYMMDD, + formatDateYYYYMMDDLocal, +} 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'; @@ -81,7 +85,7 @@ export const generatePermitHoldersReport: Resolver< // Fetches rcdPermitId from latest permit permits: { orderBy: { - createdAt: SortOrder.DESC, + expiryDate: SortOrder.DESC, }, take: 1, select: { @@ -232,7 +236,7 @@ export const generateApplicationsReport: Resolver< }, }); - // Formats the date fields and adds totalAmount, applicantName and rcdPermitId properties to allow for csv writing + // Formats the date fields and adds totalAmount, paymentRefunded, applicantName and rcdPermitId properties to allow for csv writing const csvApplications = applications.map( ({ firstName, @@ -264,7 +268,7 @@ export const generateApplicationsReport: Resolver< ...application, id: applicant?.id, dateOfBirth: dateOfBirth && formatDateYYYYMMDD(dateOfBirth), - applicationDate: createdAt ? formatDateYYYYMMDD(createdAt, true) : null, + applicationDate: createdAt ? formatDateYYYYMMDDLocal(createdAt, true) : null, applicantName: formatFullName(firstName, middleName, lastName), processingFee: `$${processingFee}`, donationAmount: `$${donationAmount}`, @@ -358,6 +362,25 @@ export const generateAccountantReport: Resolver< paymentMethod: true, }, }); + const refundMethodGroups = await prisma.application.groupBy({ + by: ['paymentMethod'], + where: { + createdAt: { + gte: startDate, + lt: endDate, + }, + applicationProcessing: { + paymentRefunded: true, + }, + }, + _sum: { + processingFee: true, + donationAmount: true, + }, + _count: { + paymentMethod: true, + }, + }); const totalAggregate = await prisma.application.aggregate({ where: { @@ -375,16 +398,48 @@ export const generateAccountantReport: Resolver< }, }); + const refundAggregate = await prisma.application.aggregate({ + where: { + createdAt: { + gte: startDate, + lt: endDate, + }, + applicationProcessing: { + paymentRefunded: true, + }, + }, + _sum: { + processingFee: true, + donationAmount: true, + }, + _count: { + paymentMethod: true, + }, + }); + const csvAccountantReportRows = []; for (const paymentMethodGroup of paymentMethodGroups) { + const refundMethodGroup = refundMethodGroups.find(group => { + return group.paymentMethod == paymentMethodGroup.paymentMethod; + }) || { _sum: { processingFee: 0, donationAmount: 0 } }; csvAccountantReportRows.push({ rowName: paymentTypeToString[paymentMethodGroup.paymentMethod], - countIssued: paymentMethodGroup._count.paymentMethod, + countIssued: paymentMethodGroup._count.paymentMethod || 0, processingFee: `$${paymentMethodGroup._sum.processingFee || 0}`, donationAmount: `$${paymentMethodGroup._sum.donationAmount || 0}`, + refundAmount: `$${Prisma.Decimal.add( + refundMethodGroup._sum.donationAmount || 0, + refundMethodGroup._sum.processingFee || 0 + )}`, totalAmount: `$${Prisma.Decimal.add( - paymentMethodGroup._sum.donationAmount || 0, - paymentMethodGroup._sum.processingFee || 0 + Prisma.Decimal.add( + paymentMethodGroup._sum.donationAmount || 0, + paymentMethodGroup._sum.processingFee || 0 + ), + -Prisma.Decimal.add( + refundMethodGroup._sum.donationAmount || 0, + refundMethodGroup._sum.processingFee || 0 + ) )}`, }); } @@ -393,9 +448,19 @@ export const generateAccountantReport: Resolver< countIssued: totalAggregate._count.paymentMethod || 0, processingFee: `$${totalAggregate._sum.processingFee || 0}`, donationAmount: `$${totalAggregate._sum.donationAmount || 0}`, + refundAmount: `$${Prisma.Decimal.add( + refundAggregate._sum.donationAmount || 0, + refundAggregate._sum.processingFee || 0 + )}`, totalAmount: `$${Prisma.Decimal.add( - totalAggregate._sum.donationAmount || 0, - totalAggregate._sum.processingFee || 0 + Prisma.Decimal.add( + totalAggregate._sum.donationAmount || 0, + totalAggregate._sum.processingFee || 0 + ), + -Prisma.Decimal.add( + refundAggregate._sum.donationAmount || 0, + refundAggregate._sum.processingFee || 0 + ) )}`, }); @@ -404,6 +469,7 @@ export const generateAccountantReport: Resolver< { id: 'countIssued', title: 'Issued #' }, { id: 'processingFee', title: 'Fees' }, { id: 'donationAmount', title: 'Donation' }, + { id: 'refundAmount', title: 'Refund' }, { id: 'totalAmount', title: 'Total' }, ]; diff --git a/lib/utils/date.ts b/lib/utils/date.ts index 0b5c9f5e..ec5fb159 100644 --- a/lib/utils/date.ts +++ b/lib/utils/date.ts @@ -22,6 +22,17 @@ export const formatDateYYYYMMDD = (d: Date, withTime = false): string => { return moment.utc(d).format(formatString); }; +/** + * Format date to be in YYYY-MM-DD format and in local time zone + * @param {Date} date date to be formatted + * @param {boolean} withTime whether to include time in formatted date + * @returns {string} formatted date + */ +export const formatDateYYYYMMDDLocal = (d: Date, withTime = false): string => { + const formatString = withTime ? 'YYYY-MM-DD, hh:mm a' : 'YYYY-MM-DD'; + return moment(d).format(formatString); +}; + /** * Format date to be in written in the following format: Sep 11 2021, 03:07 pm not converting to the local timezone * @param {Date} date date to be formatted diff --git a/lib/utils/validation.ts b/lib/utils/validation.ts index d17f00f9..379012c6 100644 --- a/lib/utils/validation.ts +++ b/lib/utils/validation.ts @@ -7,3 +7,8 @@ export const postalCodeRegex = /(^(?!.*[DFIOQU])[A-VXY][0-9][A-Z] ?[0-9][A-Z][0- * Regex to match phone numbers in the form '123-456-7890' and '1234567890' */ export const phoneNumberRegex = /(^(\d{3}-?\d{3}-?\d{4}$))/; + +/** + * Regex to match monetary values + */ +export const monetaryValueRegex = /^([0-9]+\.?[0-9]{0,2}|\.[0-9]{1,2}|)$/; diff --git a/package.json b/package.json index 39c836b8..9d56c568 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,12 @@ "generate-graphql-types": "node ./lib/scripts/generate-graphql-types.js", "reset-db": "sh lib/scripts/reset-db.sh", "lint": "yarn lint:prettier && yarn lint:eslint && yarn lint:tsc", - "lint:prettier": "prettier --check '**/*.{js,jsx,ts,tsx}'", - "lint:eslint": "eslint '**/*.{js,jsx,ts,tsx}' --cache --format stylish", + "lint:prettier": "prettier --check \"**/*.{js,jsx,ts,tsx}\"", + "lint:eslint": "eslint \"**/*.{js,jsx,ts,tsx}\" --cache --format stylish", "lint:tsc": "tsc --noemit", "fix": "yarn fix:eslint && yarn fix:prettier", - "fix:prettier": "prettier --write '**/*.{js,jsx,ts,tsx}'", - "fix:eslint": "eslint '**/*.{js,jsx,ts,tsx}' --format stylish --fix", + "fix:prettier": "prettier --write \"**/*.{js,jsx,ts,tsx}\"", + "fix:eslint": "eslint \"**/*.{js,jsx,ts,tsx}\" --format stylish --fix", "ts-node": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\"" }, "dependencies": { diff --git a/pages/admin/index.tsx b/pages/admin/index.tsx index dc801c5d..770993d4 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 { formatDateYYYYMMDD } from '@lib/utils/date'; // Date Formatter Util +import { formatDateYYYYMMDDLocal } 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 {formatDateYYYYMMDD(value, true)}; + return {formatDateYYYYMMDDLocal(value, true)}; }, }, { diff --git a/prisma/dev-seed-utils/employees.ts b/prisma/dev-seed-utils/employees.ts index c85d0df5..3b1a557f 100644 --- a/prisma/dev-seed-utils/employees.ts +++ b/prisma/dev-seed-utils/employees.ts @@ -59,6 +59,26 @@ const employees = [ lastName: 'Tsai', email: 'carelynntsai+employee@uwblueprint.org', }, + { + firstName: 'Leo', + lastName: 'Huang', + email: 'leohuang+employee@uwblueprint.org', + }, + { + firstName: 'Sherry', + lastName: 'Li', + email: 'sherryli+employee@uwblueprint.org', + }, + { + firstName: 'Chinemerem', + lastName: 'Chigbo', + email: 'chinemeremchigbo+employee@uwblueprint.org', + }, + { + firstName: 'Adil', + lastName: 'Kapadia', + email: 'adilkapadia+employee@uwblueprint.org', + }, ]; /** diff --git a/tools/admin/admin-management/graphql/delete-employee.ts b/tools/admin/admin-management/graphql/delete-employee.ts index dc45ed33..2097e2d4 100644 --- a/tools/admin/admin-management/graphql/delete-employee.ts +++ b/tools/admin/admin-management/graphql/delete-employee.ts @@ -1,15 +1,13 @@ import { Employee } from '@prisma/client'; import { gql } from '@apollo/client'; // gql tag -import { MutationDeleteEmployeeArgs } from '@lib/graphql/types'; // GraphQL types - -// TODO: FIX INPUT FORMAT OF DELETE EMPLOYEE +import { DeleteEmployeeInput } from '@lib/graphql/types'; // GraphQL types /** * GQL query to delete employee */ export const DELETE_EMPLOYEE_MUTATION = gql` - mutation DeleteEmployeeMutation($id: Int!) { - deleteEmployee(id: $id) { + mutation DeleteEmployeeMutation($input: DeleteEmployeeInput!) { + deleteEmployee(input: $input) { ok employee { firstName @@ -22,7 +20,9 @@ export const DELETE_EMPLOYEE_MUTATION = gql` /** * Input parameters for delete employee */ -export type DeleteEmployeeRequest = MutationDeleteEmployeeArgs; +export type DeleteEmployeeRequest = { + input: DeleteEmployeeInput; +}; /** * Response type of delete employee diff --git a/tools/admin/requests/create-new.ts b/tools/admin/requests/create-new.ts index 19eebaef..132d133c 100644 --- a/tools/admin/requests/create-new.ts +++ b/tools/admin/requests/create-new.ts @@ -194,6 +194,7 @@ export const INITIAL_ADDITIONAL_QUESTIONS: AdditionalInformationFormData = { // Initial data for payment details in application forms export const INITIAL_PAYMENT_DETAILS: PaymentInformationFormData = { paymentMethod: null, + processingFee: '26', donationAmount: '', shippingAddressSameAsHomeAddress: false, shippingFullName: '', diff --git a/tools/admin/requests/payment-information.ts b/tools/admin/requests/payment-information.ts index 10507c6c..b81bafb1 100644 --- a/tools/admin/requests/payment-information.ts +++ b/tools/admin/requests/payment-information.ts @@ -12,6 +12,7 @@ import { export type PaymentInformationFormData = Pick< Application, | 'donationAmount' + | 'processingFee' | 'shippingAddressSameAsHomeAddress' | 'shippingFullName' | 'shippingAddressLine1'