feat: country, state, city select
This commit is contained in:
parent
c4c8c34579
commit
65ea9e5681
|
@ -48,6 +48,7 @@
|
||||||
"contentlayer": "^0.3.4",
|
"contentlayer": "^0.3.4",
|
||||||
"eslint": "8.48.0",
|
"eslint": "8.48.0",
|
||||||
"eslint-config-next": "^14.0.1",
|
"eslint-config-next": "^14.0.1",
|
||||||
|
"geonames.js": "^3.0.6",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"lucide-react": "^0.291.0",
|
"lucide-react": "^0.291.0",
|
||||||
"monaco-jsx-highlighter": "^2.77.77",
|
"monaco-jsx-highlighter": "^2.77.77",
|
||||||
|
@ -6177,6 +6178,23 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/geonames.js": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/geonames.js/-/geonames.js-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-iDnDEzknKB7RXunjwYNgWg8ZbxjJhO9ChauXjo3njcsqhpHp3rpssqJLhATEp6T6NIybWlT/V3i6dxw+kFcICA==",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.0",
|
||||||
|
"qs": "^6.9.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/geonames.js/node_modules/axios": {
|
||||||
|
"version": "0.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||||
|
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
@ -13521,6 +13539,20 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/qs": {
|
||||||
|
"version": "6.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
|
||||||
|
"integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"side-channel": "^1.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"contentlayer": "^0.3.4",
|
"contentlayer": "^0.3.4",
|
||||||
"eslint": "8.48.0",
|
"eslint": "8.48.0",
|
||||||
"eslint-config-next": "^14.0.1",
|
"eslint-config-next": "^14.0.1",
|
||||||
|
"geonames.js": "^3.0.6",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"lucide-react": "^0.291.0",
|
"lucide-react": "^0.291.0",
|
||||||
"monaco-jsx-highlighter": "^2.77.77",
|
"monaco-jsx-highlighter": "^2.77.77",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import Geolocation from "@/components/geolocation";
|
||||||
import { PhoneInput } from "@/components/phone-input";
|
import { PhoneInput } from "@/components/phone-input";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
|
@ -57,9 +58,11 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
const [currentStep, setCurrentStep] = useState(0);
|
const [currentStep, setCurrentStep] = useState(0);
|
||||||
const [data, setData] = useState({});
|
const [data, setData] = useState({});
|
||||||
const delta = currentStep - previousStep;
|
const delta = currentStep - previousStep;
|
||||||
|
const [countryGeoId, setCountryGeoId] = useState<null | number>(null);
|
||||||
|
const [stateGeoId, setStateGeoId] = useState<null | number>(null);
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
// firstname: "",
|
// state: "",
|
||||||
jobs: [
|
jobs: [
|
||||||
{
|
{
|
||||||
jobtitle: "",
|
jobtitle: "",
|
||||||
|
@ -137,6 +140,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
"email",
|
"email",
|
||||||
"contactno",
|
"contactno",
|
||||||
"country",
|
"country",
|
||||||
|
"state",
|
||||||
"city",
|
"city",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -187,6 +191,8 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
const countries = [{ id: "1", name: "india" }];
|
const countries = [{ id: "1", name: "india" }];
|
||||||
const cities = [{ id: "1", name: "kerala" }];
|
const cities = [{ id: "1", name: "kerala" }];
|
||||||
|
|
||||||
|
console.log(form.getValues());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
@ -208,18 +214,18 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
{steps.map((step, index) => (
|
{steps.map((step, index) => (
|
||||||
<li key={step.name} className="md:flex-1">
|
<li key={step.name} className="md:flex-1">
|
||||||
{currentStep > index ? (
|
{currentStep > index ? (
|
||||||
<div className="group flex w-full flex-col border-l-4 border-sky-600 py-2 pl-4 transition-colors md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4">
|
<div className="group flex w-full flex-col border-l-4 border-primary py-2 pl-4 transition-colors md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4">
|
||||||
<span className="text-sm font-medium text-sky-600 transition-colors ">
|
<span className="text-sm font-medium text-primary transition-colors ">
|
||||||
{step.id}
|
{step.id}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm font-medium">{step.name}</span>
|
<span className="text-sm font-medium">{step.name}</span>
|
||||||
</div>
|
</div>
|
||||||
) : currentStep === index ? (
|
) : currentStep === index ? (
|
||||||
<div
|
<div
|
||||||
className="flex w-full flex-col border-l-4 border-sky-600 py-2 pl-4 md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4"
|
className="flex w-full flex-col border-l-4 border-primary py-2 pl-4 md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4"
|
||||||
aria-current="step"
|
aria-current="step"
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium text-sky-600">
|
<span className="text-sm font-medium text-primary">
|
||||||
{step.id}
|
{step.id}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm font-medium">{step.name}</span>
|
<span className="text-sm font-medium">{step.name}</span>
|
||||||
|
@ -323,7 +329,6 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
defaultCountry="IN"
|
defaultCountry="IN"
|
||||||
international
|
international
|
||||||
{...field}
|
{...field}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
@ -335,63 +340,68 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
name="country"
|
name="country"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Country</FormLabel>
|
<FormLabel
|
||||||
<Select
|
// className="block mb-[6px] mt-[2px]"
|
||||||
disabled={loading}
|
|
||||||
onValueChange={field.onChange}
|
|
||||||
value={field.value}
|
|
||||||
defaultValue={field.value}
|
|
||||||
>
|
>
|
||||||
<FormControl>
|
Country
|
||||||
<SelectTrigger>
|
</FormLabel>
|
||||||
<SelectValue
|
<Geolocation
|
||||||
defaultValue={field.value}
|
geoId={null}
|
||||||
placeholder="Select a country"
|
onChange={(country, geoId) => {
|
||||||
/>
|
setCountryGeoId(geoId);
|
||||||
</SelectTrigger>
|
field.onChange(country);
|
||||||
</FormControl>
|
}}
|
||||||
<SelectContent>
|
isCountry
|
||||||
{/* @ts-ignore */}
|
placeholderText="Select a country"
|
||||||
{countries.map((country) => (
|
searchPlaceholder="Search country..."
|
||||||
<SelectItem key={country.id} value={country.name.toLocaleLowerCase()}>
|
emptyPlaceholder="No country found"
|
||||||
{country.name}
|
isDisabled={false}
|
||||||
</SelectItem>
|
/>
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="state"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>State</FormLabel>
|
||||||
|
<Geolocation
|
||||||
|
geoId={countryGeoId}
|
||||||
|
onChange={(state, geoId) => {
|
||||||
|
setStateGeoId(geoId);
|
||||||
|
field.onChange(state);
|
||||||
|
}}
|
||||||
|
isCountry={false}
|
||||||
|
placeholderText="Select a state"
|
||||||
|
searchPlaceholder="Search state..."
|
||||||
|
emptyPlaceholder="No state found"
|
||||||
|
isDisabled={!countryGeoId}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="city"
|
name="city"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>City</FormLabel>
|
<FormLabel>City</FormLabel>
|
||||||
<Select
|
<Geolocation
|
||||||
disabled={loading}
|
geoId={stateGeoId}
|
||||||
onValueChange={field.onChange}
|
onChange={(v) => field.onChange(v)}
|
||||||
value={field.value}
|
isCountry={false}
|
||||||
defaultValue={field.value}
|
placeholderText="Select a city"
|
||||||
>
|
searchPlaceholder="Search city..."
|
||||||
<FormControl>
|
emptyPlaceholder="No city found"
|
||||||
<SelectTrigger>
|
isDisabled={!stateGeoId}
|
||||||
<SelectValue
|
/>
|
||||||
defaultValue={field.value}
|
|
||||||
placeholder="Select a city"
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
{cities.map((city) => (
|
|
||||||
<SelectItem key={city.id} value={city.name.toLocaleLowerCase()}>
|
|
||||||
{city.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -602,7 +612,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
<div>
|
<div>
|
||||||
<h1>Completed</h1>
|
<h1>Completed</h1>
|
||||||
<pre className="whitespace-pre-wrap">
|
<pre className="whitespace-pre-wrap">
|
||||||
{JSON.stringify(data)}
|
{JSON.stringify(data, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -616,11 +626,12 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<div className="mt-8 pt-5">
|
<div className="mt-8 pt-5">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={prev}
|
onClick={prev}
|
||||||
disabled={currentStep === 0}
|
disabled={currentStep === 0}
|
||||||
className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
size="icon"
|
||||||
|
// className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -636,12 +647,13 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
d="M15.75 19.5L8.25 12l7.5-7.5"
|
d="M15.75 19.5L8.25 12l7.5-7.5"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</Button>
|
||||||
<button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={next}
|
onClick={next}
|
||||||
disabled={currentStep === steps.length - 1}
|
disabled={currentStep === steps.length - 1}
|
||||||
className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
size="icon"
|
||||||
|
// className="rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -657,7 +669,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
d="M8.25 4.5l7.5 7.5-7.5 7.5"
|
d="M8.25 4.5l7.5 7.5-7.5 7.5"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Command,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandInput,
|
||||||
|
CommandItem,
|
||||||
|
CommandList,
|
||||||
|
} from "@/components/ui/command";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { FC, useEffect, useState } from "react";
|
||||||
|
import Geonames from "geonames.js";
|
||||||
|
import { FormControl } from "./ui/form";
|
||||||
|
|
||||||
|
const frameworks = [
|
||||||
|
{
|
||||||
|
value: "next.js",
|
||||||
|
label: "Next.js",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "sveltekit",
|
||||||
|
label: "SvelteKit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "nuxt.js",
|
||||||
|
label: "Nuxt.js",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "remix",
|
||||||
|
label: "Remix",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "astro",
|
||||||
|
label: "Astro",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const geonames = new Geonames({
|
||||||
|
username: "thalesandrade",
|
||||||
|
lan: "en",
|
||||||
|
encoding: "JSON",
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
geoId: number | null;
|
||||||
|
onChange: (country: string, geoId: number) => void;
|
||||||
|
isCountry: boolean;
|
||||||
|
placeholderText: string;
|
||||||
|
searchPlaceholder: string;
|
||||||
|
emptyPlaceholder: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Geolocation: FC<Props> = ({
|
||||||
|
geoId,
|
||||||
|
onChange,
|
||||||
|
isCountry,
|
||||||
|
placeholderText,
|
||||||
|
searchPlaceholder,
|
||||||
|
emptyPlaceholder,
|
||||||
|
isDisabled,
|
||||||
|
}) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [currentValue, setCurrentValue] = useState<null | number>(null);
|
||||||
|
const [options, setOptions] = useState<
|
||||||
|
{ countryName: string; geonameId: number; name: string }[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
const data = () => {
|
||||||
|
isCountry
|
||||||
|
? geonames.countryInfo({}).then((res: any) => {
|
||||||
|
console.log(res);
|
||||||
|
setOptions(res.geonames);
|
||||||
|
})
|
||||||
|
: geonames.children({ geonameId: geoId }).then((res: any) => {
|
||||||
|
if (res.totalResultsCount) setOptions(res.geonames);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
data();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}, [geoId, isCountry]);
|
||||||
|
|
||||||
|
const currentPlaceholderText =
|
||||||
|
currentValue && isCountry
|
||||||
|
? options.find((option: any) => option.geonameId === currentValue)
|
||||||
|
?.countryName
|
||||||
|
: currentValue
|
||||||
|
? options.find((option: any) => option.geonameId === currentValue)?.name
|
||||||
|
: placeholderText;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
|
<PopoverTrigger asChild disabled={isDisabled}>
|
||||||
|
<FormControl>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
role="combobox"
|
||||||
|
aria-expanded={open}
|
||||||
|
className="w-full justify-between"
|
||||||
|
>
|
||||||
|
{currentPlaceholderText}
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
</Button>
|
||||||
|
</FormControl>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-[200px] md:w-[400px] p-0">
|
||||||
|
<Command>
|
||||||
|
<CommandList>
|
||||||
|
<CommandInput placeholder={searchPlaceholder} className="h-9" />
|
||||||
|
<CommandEmpty>{emptyPlaceholder}</CommandEmpty>
|
||||||
|
<CommandGroup>
|
||||||
|
{options.map((v: any, index) => (
|
||||||
|
<CommandItem
|
||||||
|
key={index}
|
||||||
|
value={v.geonameId}
|
||||||
|
onSelect={() => {
|
||||||
|
setCurrentValue(
|
||||||
|
v.geonameId === currentValue ? null : v.geonameId,
|
||||||
|
);
|
||||||
|
const name = isCountry ? v.countryName : v.name;
|
||||||
|
onChange(
|
||||||
|
v.geonameId === currentValue ? "" : name,
|
||||||
|
v.geonameId === currentValue ? null : v.geonameId,
|
||||||
|
);
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isCountry ? v.countryName : v.name}
|
||||||
|
<CheckIcon
|
||||||
|
className={cn(
|
||||||
|
"ml-auto h-4 w-4",
|
||||||
|
currentValue === v.geonameId
|
||||||
|
? "opacity-100"
|
||||||
|
: "opacity-0",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</CommandGroup>
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Geolocation;
|
|
@ -117,7 +117,7 @@ const CommandItem = React.forwardRef<
|
||||||
<CommandPrimitive.Item
|
<CommandPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
|
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -3,28 +3,42 @@ import { isValidPhoneNumber } from "react-phone-number-input";
|
||||||
|
|
||||||
export const profileSchema = z.object({
|
export const profileSchema = z.object({
|
||||||
firstname: z
|
firstname: z
|
||||||
.string()
|
.string({ required_error: "Please enter your first name" })
|
||||||
.min(3, { message: "First name must be at least 3 characters" }),
|
.trim()
|
||||||
|
.min(1, { message: "Please enter your first name" }),
|
||||||
lastname: z
|
lastname: z
|
||||||
.string()
|
.string({ required_error: "Please enter your last name" })
|
||||||
.min(3, { message: "Last name must be at least 3 characters" }),
|
.trim()
|
||||||
|
.min(1, { message: "Please enter your last name" }),
|
||||||
email: z
|
email: z
|
||||||
.string()
|
.string({ required_error: "Please enter your email" })
|
||||||
.email({ message: "Invalid email" }),
|
.email({ message: "Please enter a valid email" }),
|
||||||
contactno: z.string({required_error: "Number is required"}).refine((value) => isValidPhoneNumber(value), {message: "Invalid number"}),
|
contactno: z
|
||||||
country: z.string().min(1, { message: "Please select a category" }),
|
.string({ required_error: "Please enter your phone number" })
|
||||||
city: z.string().min(1, { message: "Please select a category" }),
|
.refine((value) => isValidPhoneNumber(value), {
|
||||||
|
message: "Please enter a valid phone number",
|
||||||
|
}),
|
||||||
|
country: z
|
||||||
|
.string({ required_error: "Please select your country" })
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Please select your country" }),
|
||||||
|
state: z
|
||||||
|
.string({ required_error: "Please select your state" })
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Please select your state" }),
|
||||||
|
city: z
|
||||||
|
.string({ required_error: "Please select your city" })
|
||||||
|
.trim()
|
||||||
|
.min(1, { message: "Please select your city" }),
|
||||||
// jobs array is for the dynamic fields
|
// jobs array is for the dynamic fields
|
||||||
jobs: z.array(
|
jobs: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
jobcountry: z.string().min(1, { message: "Please select a country" }),
|
jobcountry: z.string().min(1, { message: "Please select a country" }),
|
||||||
jobcity: z.string().min(1, { message: "Please select a city" }),
|
jobcity: z.string().min(1, { message: "Please select a city" }),
|
||||||
jobtitle: z
|
jobtitle: z.string(),
|
||||||
.string(),
|
// .min(3, { message: "First Name must be at least 3 characters" }),
|
||||||
// .min(3, { message: "First Name must be at least 3 characters" }),
|
employer: z.string(),
|
||||||
employer: z
|
// .min(3, { message: "First Name must be at least 3 characters" }),
|
||||||
.string(),
|
|
||||||
// .min(3, { message: "First Name must be at least 3 characters" }),
|
|
||||||
startdate: z
|
startdate: z
|
||||||
.string()
|
.string()
|
||||||
.refine((value) => /^\d{4}-\d{2}-\d{2}$/.test(value), {
|
.refine((value) => /^\d{4}-\d{2}-\d{2}$/.test(value), {
|
||||||
|
|
Loading…
Reference in New Issue