From 26e15360f798d70a02325e2721eeaf52817b6a4e Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Fri, 3 Jul 2026 16:07:08 +0530 Subject: [PATCH] feat(ticket): add due date picker and contractor details to assign flow --- package-lock.json | 73 ++++-- package.json | 3 + .../components/actions/AssignTicketAction.tsx | 57 ++++- src/components/async-select/AsyncSelect.tsx | 23 +- .../async-select/AsyncSelect.types.ts | 5 +- src/components/form/DatePicker.tsx | 171 ++++++++++++++ .../lookups/AssignableWorkerSelect.tsx | 31 ++- .../lookups/AssignableWorkerSelect.types.ts | 4 +- src/components/ui/button.tsx | 58 ++--- src/components/ui/calendar.tsx | 220 ++++++++++++++++++ src/components/ui/drawer.tsx | 135 +++++++++++ src/types/ticket/actions.ts | 7 + 12 files changed, 723 insertions(+), 64 deletions(-) create mode 100644 src/components/form/DatePicker.tsx create mode 100644 src/components/ui/calendar.tsx create mode 100644 src/components/ui/drawer.tsx diff --git a/package-lock.json b/package-lock.json index 48011ee..5a70359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "axios": "^1.13.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.4.0", "libphonenumber-js": "^1.13.7", "lucide-react": "^0.548.0", "motion": "^12.38.0", @@ -34,11 +35,13 @@ "next-themes": "^0.4.6", "radix-ui": "^1.6.0", "react": "19.2.0", + "react-day-picker": "^10.0.1", "react-dom": "19.2.0", "react-hook-form": "^7.79.0", "recharts": "2.15.4", "sonner": "^1.7.4", "tailwind-merge": "^3.3.1", + "vaul": "^1.1.2", "zod": "^4.4.3", "zustand": "^5.0.14" }, @@ -403,6 +406,12 @@ } } }, + "node_modules/@date-fns/tz": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.5.0.tgz", + "integrity": "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==", + "license": "MIT" + }, "node_modules/@emnapi/core": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", @@ -4780,6 +4789,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -7979,6 +7998,32 @@ "node": ">=0.10.0" } }, + "node_modules/react-day-picker": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-10.0.1.tgz", + "integrity": "sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "date-fns": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "@types/react": ">=16.8.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "19.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", @@ -9215,6 +9260,19 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/victory-vendor": { "version": "36.9.2", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", @@ -9422,21 +9480,6 @@ "optional": true } } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz", - "integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } } } } diff --git a/package.json b/package.json index 80c37cb..bab90e3 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "axios": "^1.13.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.4.0", "libphonenumber-js": "^1.13.7", "lucide-react": "^0.548.0", "motion": "^12.38.0", @@ -38,11 +39,13 @@ "next-themes": "^0.4.6", "radix-ui": "^1.6.0", "react": "19.2.0", + "react-day-picker": "^10.0.1", "react-dom": "19.2.0", "react-hook-form": "^7.79.0", "recharts": "2.15.4", "sonner": "^1.7.4", "tailwind-merge": "^3.3.1", + "vaul": "^1.1.2", "zod": "^4.4.3", "zustand": "^5.0.14" }, diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/AssignTicketAction.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/AssignTicketAction.tsx index 420e7d8..4e138cc 100644 --- a/src/app/(modules)/ticket/[ticketId]/components/actions/AssignTicketAction.tsx +++ b/src/app/(modules)/ticket/[ticketId]/components/actions/AssignTicketAction.tsx @@ -1,56 +1,93 @@ 'use client'; import { useState } from 'react'; -import { Send, UserPlus } from 'lucide-react'; +import { Users, Mail, Phone, Send, ShieldCheck } from 'lucide-react'; +import { DatePicker } from '@/components/form/DatePicker'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { AssignableWorkerSelect } from '@/components/lookups/AssignableWorkerSelect'; -import type { TicketDetail } from '@/types'; +import type { AssignableTicketUser, TicketDetail } from '@/types'; import { useAssignTicketMutation } from '../../../hooks/useTicketQueries'; import { TicketActionCard } from './TicketActionCard'; export function AssignTicketAction({ ticket }: { ticket: TicketDetail }) { const [selectedUserId, setSelectedUserId] = useState(''); + const [selectedContractor, setSelectedContractor] = + useState(null); + const [dueDate, setDueDate] = useState(); const [assignNote, setAssignNote] = useState(''); const assignMutation = useAssignTicketMutation(ticket.id); return ( - +
- + { + setSelectedUserId(userId); + setSelectedContractor(user); + }} disabled={assignMutation.isPending} />
+ {selectedContractor ? ( +
+

Contractor Details

+ {selectedContractor.phone_number ? ( +

+ + {selectedContractor.phone_number} +

+ ) : null} +

+ + {selectedContractor.email} +

+

+ + {selectedContractor.role.name} +

+
+ ) : null}
- + + +
+
+