Skip to content

Instantly share code, notes, and snippets.

@azeezat
Last active January 9, 2026 16:10
Show Gist options
  • Select an option

  • Save azeezat/a2262bcaee1556107d44c6e0950188cb to your computer and use it in GitHub Desktop.

Select an option

Save azeezat/a2262bcaee1556107d44c6e0950188cb to your computer and use it in GitHub Desktop.
'use client';
import React from 'react';
import { Form } from 'radix-ui';
import { Flex } from '@radix-ui/themes';
import {
RequestCategory,
RequestInput,
} from '@/backend/graphql/generated/types.generated';
import { SearchableDropdown } from '@/frontend/components/dropdown/searchable-dropdown';
import { FileUpload } from './upload-file';
interface RequestFormProps {
createRequestData: RequestInput;
setCreateRequestData: (createRequestData: RequestInput) => void;
requestCategories: RequestCategory[];
loadingCategories: boolean;
files: File[];
setFiles: (value: File[]) => void;
hideUpload?: boolean;
errors: Record<string, string>;
}
export const RequestForm = ({
createRequestData,
setCreateRequestData,
requestCategories,
loadingCategories,
files,
setFiles,
hideUpload,
errors,
}: RequestFormProps) => {
return (
<Form.Root>
<Form.Field className="Field" name="title">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Title</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter your title
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid title
</Form.Message>
</Flex>
<Form.Control asChild>
<input
className="Input"
value={createRequestData.title}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
title: e.target.value,
})
}
//required
/>
</Form.Control>
{errors?.['title'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['title']}
</Form.Message>
)}
</Form.Field>
<Form.Field className="Field" name="description">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Description</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter request description
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid description
</Form.Message>
</Flex>
<Form.Control asChild>
<textarea
className="Textarea"
value={createRequestData.description}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
description: e.target.value || '',
})
}
//required
/>
</Form.Control>
{errors?.['description'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['description']}
</Form.Message>
)}
</Form.Field>
<Form.Field className="Field" name="budget">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Budget Per Companion</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter a budget
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid budget
</Form.Message>
</Flex>
<Form.Control asChild>
<input
className="Input"
type="number"
min={1}
value={createRequestData.budget}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
budget: e.target.value || '',
})
}
//required
/>
</Form.Control>
{errors?.['budget'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['budget']}
</Form.Message>
)}
</Form.Field>
<Form.Field className="Field" name="date">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Date</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter start date
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid start date
</Form.Message>
</Flex>
<Form.Control asChild>
<Flex direction="row" gap="2" align="center">
<div>
<input
className="Input"
type="datetime-local"
value={createRequestData.startDateTime as string}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
startDateTime: e.target.value || '',
})
}
//required
/>
{errors?.['startDateTime'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['startDateTime']}
</Form.Message>
)}
</div>
<div>
<input
className="Input"
type="datetime-local"
value={createRequestData.endDateTime as string}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
endDateTime: e.target.value || '',
})
}
//required
/>
{errors?.['endDateTime'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['endDateTime']}
</Form.Message>
)}
</div>
</Flex>
</Form.Control>
</Form.Field>
<Form.Field className="Field" name="location">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Location</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter location
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid location
</Form.Message>
</Flex>
<Form.Control asChild>
<input
className="Input"
type="text"
value={createRequestData.location}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
location: e.target.value || '',
})
}
//required
/>
</Form.Control>
{errors?.['location'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['location']}
</Form.Message>
)}
</Form.Field>
<Form.Field className="Field" name="title">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Number of companions</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter your number of companions
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid number
</Form.Message>
</Flex>
<Form.Control asChild>
<input
className="Input"
type="number"
value={createRequestData.numberOfCompanions}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
numberOfCompanions: Number(e.target.value || 0),
})
}
//required
/>
</Form.Control>
{errors?.['numberOfCompanions'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['numberOfCompanions']}
</Form.Message>
)}
</Form.Field>
<Form.Field name="category">
<Form.Label className="Label">Category</Form.Label>
<SearchableDropdown
options={
requestCategories?.map((item) => ({
label: item.name as string,
value: item.id as number,
})) || []
}
value={{
value: createRequestData.categoryId,
label: requestCategories.find(() => createRequestData.categoryId)
?.name as string,
}}
onChange={(category: any) =>
setCreateRequestData({
...createRequestData,
categoryId: category.value,
})
}
//required
isDisabled={loadingCategories}
/>
{errors?.['categoryId'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['categoryId']}
</Form.Message>
)}
</Form.Field>
<Form.Field className="Field" name="companionDistance">
<Flex justify="between" align="baseline">
<Form.Label className="Label">Companion distance</Form.Label>
<Form.Message className="Message" match="valueMissing">
Please enter your companion distance
</Form.Message>
<Form.Message className="Message" match="typeMismatch">
Please provide a valid companion distance
</Form.Message>
</Flex>
<Form.Control asChild>
<input
className="Input"
min={1}
value={createRequestData.companionDistance || 0}
onChange={(e) =>
setCreateRequestData({
...createRequestData,
companionDistance: Number(e.target.value),
})
}
/>
</Form.Control>
{errors?.['companionDistance'] && (
<Form.Message className="text-[13px] text-red-500 opacity-80">
{errors['companionDistance']}
</Form.Message>
)}
</Form.Field>
{!hideUpload && (
<Form.Field name="files">
<FileUpload files={files} setFiles={setFiles} />
</Form.Field>
)}
</Form.Root>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment