From a42317fb22b8eecce51c73f9494530f46055a3ca Mon Sep 17 00:00:00 2001 From: Paribesh Nepal <nepalparibesh01@gmail.com> Date: Tue, 15 Oct 2024 00:54:29 +0530 Subject: [PATCH] feat: ui change for the calender --- package.json | 3 + src/components/job-form.tsx | 121 +++++++++++++++++++-------------- src/components/ui/calendar.tsx | 66 ++++++++++++++++++ 3 files changed, 139 insertions(+), 51 deletions(-) create mode 100644 src/components/ui/calendar.tsx diff --git a/package.json b/package.json index a97eb2f2..c6562990 100644 --- a/package.json +++ b/package.json @@ -54,10 +54,12 @@ "@types/lodash": "^4.17.7", "@types/uuid": "^10.0.0", "@uidotdev/usehooks": "^2.4.1", + "100xdevs-job-board": "file:", "bcryptjs": "^2.4.3", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", + "date-fns": "^2.30.0", "dayjs": "^1.11.13", "framer-motion": "^11.9.0", "jiti": "^1.21.6", @@ -71,6 +73,7 @@ "node-cron": "^3.0.3", "nodemailer": "^6.9.15", "react": "^18", + "react-day-picker": "^8.10.1", "react-dom": "^18", "react-hook-form": "^7.52.2", "react-icons": "^5.2.1", diff --git a/src/components/job-form.tsx b/src/components/job-form.tsx index add6f3b4..55ffa36a 100644 --- a/src/components/job-form.tsx +++ b/src/components/job-form.tsx @@ -25,7 +25,12 @@ import { import { Button } from './ui/button'; import { Input } from './ui/input'; import { useToast } from './ui/use-toast'; -import { Calendar, LucideRocket, MailOpenIcon, X } from 'lucide-react'; +import { + Calendar as CalendarIcon, + LucideRocket, + MailOpenIcon, + X, +} from 'lucide-react'; import DescriptionEditor from './DescriptionEditor'; import Image from 'next/image'; import { FaFileUpload } from 'react-icons/fa'; @@ -33,6 +38,7 @@ import { Switch } from './ui/switch'; import { Label } from './ui/label'; import dynamic from 'next/dynamic'; import { uploadFileAction } from '@/actions/upload-to-cdn'; +import { format } from 'date-fns'; const DynamicGmapsAutoSuggest = dynamic(() => import('./gmaps-autosuggest'), { ssr: false, @@ -43,6 +49,8 @@ import { useSession } from 'next-auth/react'; import { useRouter } from 'next/navigation'; import APP_PATHS from '@/config/path.config'; import { SkillsCombobox } from './skills-combobox'; +import { Popover, PopoverContent, PopoverTrigger } from './ui/popover'; +import { Calendar } from '@/components/ui/calendar'; const PostJobForm = () => { const session = useSession(); @@ -203,7 +211,7 @@ const PostJobForm = () => { <div className="flex flex-col items-center w-[30rem] gap-y-10 justify-center mb-20"> <div className="w-full md:justify-center mt-4 flex flex-col md:flex-row gap-2"> <div className="bg-gray-800/90 backdrop-blur-sm p-4 rounded-lg text-center text-white w-full md:w-48"> - <Calendar className="w-8 h-8 mb-3 mx-auto text-green-500" /> + <CalendarIcon className="w-8 h-8 mb-3 mx-auto text-green-500" /> <p className="text-base font-semibold mb-1">Posted for</p> <p className="text-gray-400 text-sm">30 days</p> </div> @@ -509,65 +517,76 @@ const PostJobForm = () => { )} </div> </div> - <div className="flex flex-col-2 gap-2"> - <div className="flex flex-col gap-2"> - <div className=""> - <Label>Expiry date</Label> - </div> - <div> + <div className="flex flex-col gap-2"> + <Label>Expiry date</Label> + <FormField + control={form.control} + name="hasExpiryDate" + render={({ field }) => ( + <FormItem className="flex items-center space-y-0 gap-2"> + <FormControl> + <Switch + checked={field.value} + onCheckedChange={field.onChange} + className="data-[state=checked]:bg-gray-300 data-[state=unchecked]:bg-gray-400" + /> + </FormControl> + <FormLabel className="mt-0"> + Does this job posting have an expiry date? + </FormLabel> + </FormItem> + )} + /> + + {watchHasExpiryDate && ( + <div className="flex gap-4"> <FormField control={form.control} - name="hasExpiryDate" + name="expiryDate" render={({ field }) => ( - <FormItem className="flex items-center space-y-0 gap-2"> + <FormItem className="flex-1"> + <div className="space-y-0.5"></div> <FormControl> - <Switch - checked={field.value} - onCheckedChange={field.onChange} - className="data-[state=checked]:bg-gray-300 data-[state=unchecked]:bg-gray-400" - /> + <Popover> + <PopoverTrigger asChild> + <Button + variant="outline" + className={`w-[240px] pl-3 text-left font-normal bg-gray-800 + `} // No color change on hover + > + {field.value ? ( + format(new Date(field.value), 'PPP') + ) : ( + <span>Pick a date</span> + )} + <span className="ml-auto">📅</span> + </Button> + </PopoverTrigger> + <PopoverContent + className="w-auto p-0" + align="start" + > + <Calendar + mode="single" + aria-selected={field.value} + onSelect={(date: any) => { + field.onChange(date); // Update the field value with the selected date + }} + aria-disabled={(date: any) => + date > new Date() || + date < new Date('1900-01-01') + } + /> + </PopoverContent> + </Popover> </FormControl> - - <FormLabel className="mt-0"> - Does this job posting have an expiry date? - </FormLabel> + <FormMessage /> </FormItem> )} /> </div> - {watchHasExpiryDate && ( - <div className="flex gap-4"> - <FormField - control={form.control} - name="expiryDate" - render={({ field }) => ( - <FormItem className="flex-1"> - <div className="space-y-0.5"></div> - <FormControl> - <Input - {...field} - type="date" - className=" w-2/5- bg-gray-800 border-gray-400" - placeholder="Select expiry date" - value={ - field.value - ? field.value.toISOString().split('T')[0] - : '' - } - onChange={(e) => - field.onChange(new Date(e.target.value)) - } - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - </div> - )} - </div> + )} </div> - <div className="space-y-2"> <FormLabel className="font-medium">Location</FormLabel> <DynamicGmapsAutoSuggest diff --git a/src/components/ui/calendar.tsx b/src/components/ui/calendar.tsx new file mode 100644 index 00000000..b45df763 --- /dev/null +++ b/src/components/ui/calendar.tsx @@ -0,0 +1,66 @@ +'use client'; + +import * as React from 'react'; +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import { DayPicker } from 'react-day-picker'; + +import { cn } from '@/lib/utils'; +import { buttonVariants } from '@/components/ui/button'; + +export type CalendarProps = React.ComponentProps<typeof DayPicker>; + +function Calendar({ + className, + classNames, + showOutsideDays = true, + ...props +}: CalendarProps) { + return ( + <DayPicker + showOutsideDays={showOutsideDays} + className={cn('p-3', className)} + classNames={{ + months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0', + month: 'space-y-4', + caption: 'flex justify-center pt-1 relative items-center', + caption_label: 'text-sm font-medium', + nav: 'space-x-1 flex items-center', + nav_button: cn( + buttonVariants({ variant: 'outline' }), + 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100' + ), + nav_button_previous: 'absolute left-1', + nav_button_next: 'absolute right-1', + table: 'w-full border-collapse space-y-1', + head_row: 'flex', + head_cell: + 'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]', + row: 'flex w-full mt-2', + cell: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20', + day: cn( + buttonVariants({ variant: 'ghost' }), + 'h-9 w-9 p-0 font-normal aria-selected:opacity-100' + ), + day_range_end: 'day-range-end', + day_selected: + 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground', + day_today: 'bg-accent text-accent-foreground', + day_outside: + 'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30', + day_disabled: 'text-muted-foreground opacity-50', + day_range_middle: + 'aria-selected:bg-accent aria-selected:text-accent-foreground', + day_hidden: 'invisible', + ...classNames, + }} + components={{ + IconLeft: () => <ChevronLeft className="h-4 w-4" />, + IconRight: () => <ChevronRight className="h-4 w-4" />, + }} + {...props} + /> + ); +} +Calendar.displayName = 'Calendar'; + +export { Calendar };