{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"apply-form","type":"registry:ui","title":"ApplyForm","description":"A candidate application. Anonymous applications are supported by the backend.","package":"job-board","dependencies":["@particle-academy\/react-fancy"],"registryDependencies":["types"],"files":[{"path":"components\/fancy\/apply-form\/ApplyForm.tsx","content":"import { Button, Callout, Card, Heading, Input, Text, Textarea } from '@particle-academy\/react-fancy';\r\nimport { useState } from 'react';\r\nimport type { JobApplicationInput, JobPosting } from '..\/types';\r\n\r\nexport interface ApplyFormProps {\r\n    posting: JobPosting;\r\n    onSubmit: (input: JobApplicationInput) => void | Promise<void>;\r\n    onCancel?: () => void;\r\n    submitting?: boolean;\r\n    \/** Server-side validation errors, keyed by field. *\/\r\n    errors?: Partial<Record<keyof JobApplicationInput, string>>;\r\n    \/** Prefill from the signed-in candidate's profile. *\/\r\n    defaults?: JobApplicationInput;\r\n    className?: string;\r\n}\r\n\r\n\/** The candidate's application form. *\/\r\nexport function ApplyForm({\r\n    posting,\r\n    onSubmit,\r\n    onCancel,\r\n    submitting = false,\r\n    errors = {},\r\n    defaults = {},\r\n    className,\r\n}: ApplyFormProps) {\r\n    const [values, setValues] = useState<JobApplicationInput>({\r\n        cover_letter: defaults.cover_letter ?? '',\r\n        contact_email: defaults.contact_email ?? '',\r\n        contact_phone: defaults.contact_phone ?? '',\r\n    });\r\n\r\n    const patch = (next: Partial<JobApplicationInput>) =>\r\n        setValues((current) => ({ ...current, ...next }));\r\n\r\n    return (\r\n        <Card\r\n            variant=\"outlined\"\r\n            padding=\"lg\"\r\n            className={`!rounded-xl !border-secondary-200 !bg-white !shadow-sm ${className ?? ''}`}\r\n        >\r\n            <Heading as=\"h2\" size=\"lg\" weight=\"bold\" className=\"!text-secondary-900\">\r\n                Apply for {posting.title}\r\n            <\/Heading>\r\n            {posting.employer?.name && (\r\n                <Text size=\"sm\" color=\"muted\" className=\"!mt-1\">\r\n                    {posting.employer.name}\r\n                <\/Text>\r\n            )}\r\n\r\n            {!posting.accepts_applications && (\r\n                <Callout color=\"red\" className=\"!mt-4\">\r\n                    <Text size=\"sm\">This posting is no longer accepting applications.<\/Text>\r\n                <\/Callout>\r\n            )}\r\n\r\n            <form\r\n                className=\"mt-5 grid gap-4\"\r\n                onSubmit={(e) => {\r\n                    e.preventDefault();\r\n                    void onSubmit(values);\r\n                }}\r\n            >\r\n                <Textarea\r\n                    label=\"Why you're a good fit\"\r\n                    description=\"Optional, but it helps.\"\r\n                    minRows={5}\r\n                    autoResize\r\n                    value={values.cover_letter ?? ''}\r\n                    onValueChange={(cover_letter) => patch({ cover_letter })}\r\n                    error={errors.cover_letter}\r\n                \/>\r\n\r\n                <div className=\"grid gap-4 sm:grid-cols-2\">\r\n                    <Input\r\n                        type=\"email\"\r\n                        label=\"Contact email\"\r\n                        value={values.contact_email ?? ''}\r\n                        onValueChange={(contact_email) => patch({ contact_email })}\r\n                        error={errors.contact_email}\r\n                    \/>\r\n                    <Input\r\n                        type=\"tel\"\r\n                        label=\"Contact phone\"\r\n                        value={values.contact_phone ?? ''}\r\n                        onValueChange={(contact_phone) => patch({ contact_phone })}\r\n                        error={errors.contact_phone}\r\n                    \/>\r\n                <\/div>\r\n\r\n                <div className=\"flex items-center justify-end gap-3 pt-1\">\r\n                    {onCancel && (\r\n                        <Button\r\n                            type=\"button\"\r\n                            variant=\"ghost\"\r\n                            onClick={onCancel}\r\n                            className=\"!text-secondary-700 hover:!text-brand !px-4 !py-2\"\r\n                        >\r\n                            Cancel\r\n                        <\/Button>\r\n                    )}\r\n                    <Button\r\n                        type=\"submit\"\r\n                        loading={submitting}\r\n                        disabled={submitting || !posting.accepts_applications}\r\n                        className=\"!bg-brand hover:!bg-primary-600 disabled:!bg-secondary-300 !text-white !font-semibold !px-6 !py-2.5 !rounded-md !shadow-sm\"\r\n                    >\r\n                        {submitting ? 'Sending\u2026' : 'Submit application'}\r\n                    <\/Button>\r\n                <\/div>\r\n            <\/form>\r\n        <\/Card>\r\n    );\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/apply-form\/ApplyForm.tsx"}]}