Last active
January 9, 2026 16:09
-
-
Save azeezat/b2880cc2f6163b82b0d157416a8afafa to your computer and use it in GitHub Desktop.
the logical part of the create request page
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 'use client'; | |
| import React, { useState } from 'react'; | |
| import { DialogComponent } from '@/frontend/components/dialog/dialog'; | |
| import { Form } from 'radix-ui'; | |
| import { | |
| FileUploadInput, | |
| MutationcreateRequestArgs, | |
| Request, | |
| RequestCategory, | |
| RequestInput, | |
| UploadedFile, | |
| } from '@/backend/graphql/generated/types.generated'; | |
| import { useMutation, useQuery } from '@apollo/client/react'; | |
| import { UPLOAD_FILES_MUTATION } from '@/frontend/data/graphql-api/uploads'; | |
| import { useToastStore } from '@/frontend/store/toast-store'; | |
| import { | |
| CREATE_REQUEST_MUTATION, | |
| GET_REQUESTS_QUERY, | |
| REQUEST_CATEGORY_QUERY, | |
| } from '@/frontend/data/graphql-api/requests'; | |
| import { toGraphQLDateTime } from '@/frontend/utils/string-utils'; | |
| import { RequestForm } from './request-form'; | |
| import { validateFiles } from '@/backend/utils/helpers'; | |
| import { errorsByField } from '@/frontend/utils/error-utils'; | |
| interface CreateRequestDialogProps { | |
| open: boolean; | |
| setOpen: (value: boolean) => void; | |
| setOpenPaymentMethod: (value: boolean) => void; | |
| setRequestId: (value: string) => void; | |
| } | |
| export const CreateRequestDialog = ({ | |
| open, | |
| setOpen, | |
| setOpenPaymentMethod, | |
| setRequestId, | |
| }: CreateRequestDialogProps) => { | |
| const { pushToast } = useToastStore(); | |
| const initialCreateRequestData: RequestInput = { | |
| title: '', | |
| description: '', | |
| budget: 0, | |
| numberOfCompanions: 1, | |
| startDateTime: '', | |
| endDateTime: '', | |
| location: '', | |
| categoryId: 0, | |
| companionDistance: 1, | |
| }; | |
| const [createRequestData, setCreateRequestData] = useState<RequestInput>( | |
| initialCreateRequestData | |
| ); | |
| const [errors, setErrors] = useState<Record<string, string>>({}); | |
| const [files, setFiles] = useState<File[]>(); | |
| const { data: requestCategories, loading: loadingCategories } = useQuery<{ | |
| requestCategories: RequestCategory[]; | |
| }>(REQUEST_CATEGORY_QUERY); | |
| /**Create request mutation */ | |
| const [createRequestMutation, { loading: creatingRequest }] = useMutation< | |
| { | |
| createRequest: Request; | |
| }, | |
| MutationcreateRequestArgs | |
| >(CREATE_REQUEST_MUTATION, { | |
| refetchQueries: [ | |
| { | |
| query: GET_REQUESTS_QUERY, | |
| variables: { | |
| page: 1, | |
| limit: 10, | |
| }, | |
| }, | |
| ], | |
| }); | |
| const handleCreateRequest = () => { | |
| if (files?.length) { | |
| const fileValidationError = validateFiles(files, 2); | |
| if (fileValidationError) { | |
| pushToast({ | |
| type: 'error', | |
| description: fileValidationError, | |
| }); | |
| return; | |
| } | |
| } | |
| createRequestMutation({ | |
| variables: { | |
| input: { | |
| ...createRequestData, | |
| startDateTime: toGraphQLDateTime( | |
| createRequestData.startDateTime as string | |
| ), | |
| endDateTime: toGraphQLDateTime( | |
| createRequestData.endDateTime as string | |
| ), | |
| }, | |
| }, | |
| onCompleted: (data) => { | |
| setErrors({}); | |
| setRequestId(data.createRequest.id as string); | |
| if (files?.length) { | |
| handleUpload(data.createRequest.id as string); | |
| return; | |
| } | |
| setOpenPaymentMethod(true); | |
| }, | |
| onError: (error) => { | |
| //@ts-expect-error Known errors in apollo | |
| const err = errorsByField(error.errors?.[0]?.extensions?.issues || []); | |
| setErrors(err); | |
| pushToast({ | |
| type: 'error', | |
| description: `Failed to create request. ${error}`, | |
| }); | |
| }, | |
| }); | |
| }; | |
| /**Upload files mutation */ | |
| const [uploadFileMutation, { loading: uploadingRequestFiles }] = useMutation< | |
| { | |
| uploadedFiles: UploadedFile[]; | |
| }, | |
| { files: File[]; input: FileUploadInput } | |
| >(UPLOAD_FILES_MUTATION); | |
| const handleUpload = (entityId: string) => { | |
| uploadFileMutation({ | |
| variables: { | |
| files: files as File[], | |
| input: { | |
| entityId, | |
| purpose: 'REQUEST', | |
| }, | |
| }, | |
| onCompleted: () => { | |
| setOpenPaymentMethod(true); | |
| }, | |
| onError: (error) => { | |
| pushToast({ | |
| type: 'error', | |
| description: `Upload failed: ${error.message}`, | |
| }); | |
| }, | |
| }); | |
| }; | |
| const resetPage = () => { | |
| setOpen(false); | |
| setFiles(undefined); | |
| setCreateRequestData(initialCreateRequestData); | |
| }; | |
| return ( | |
| <DialogComponent | |
| open={open} | |
| onOpenChange={(value) => { | |
| setOpen(value); | |
| setFiles(undefined); | |
| setCreateRequestData(initialCreateRequestData); | |
| }} | |
| lock | |
| title="Create Request" | |
| footer={ | |
| <div className="flex justify-end gap-2"> | |
| <button | |
| onClick={() => resetPage()} | |
| className="rounded-xl border border-neutral-300 px-3 py-2 text-sm hover:bg-neutral-50 dark:border-neutral-700" | |
| disabled={creatingRequest} | |
| > | |
| Cancel | |
| </button> | |
| <Form.Submit asChild> | |
| <button | |
| className="rounded-xl bg-black px-3 py-2 text-sm text-white hover:opacity-90 dark:bg-white dark:text-black" | |
| type="submit" | |
| onClick={handleCreateRequest} | |
| disabled={creatingRequest} | |
| > | |
| {creatingRequest || uploadingRequestFiles | |
| ? 'Creating...' | |
| : 'Create Request'} | |
| </button> | |
| </Form.Submit> | |
| </div> | |
| } | |
| > | |
| <RequestForm | |
| files={files as File[]} | |
| setFiles={setFiles} | |
| createRequestData={createRequestData} | |
| setCreateRequestData={setCreateRequestData} | |
| requestCategories={requestCategories?.requestCategories || []} | |
| loadingCategories={loadingCategories} | |
| errors={errors} | |
| /> | |
| </DialogComponent> | |
| ); | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment