feat: add phone input field in profile form
This commit is contained in:
parent
40265d8c72
commit
c4c8c34579
|
@ -44,6 +44,7 @@
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"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",
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
"react-error-boundary": "^4.0.13",
|
"react-error-boundary": "^4.0.13",
|
||||||
"react-error-overlay": "^6.0.11",
|
"react-error-overlay": "^6.0.11",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.47.0",
|
||||||
|
"react-phone-number-input": "^3.4.0",
|
||||||
"react-resizable-panels": "^2.0.16",
|
"react-resizable-panels": "^2.0.16",
|
||||||
"rehype-pretty-code": "^0.13.1",
|
"rehype-pretty-code": "^0.13.1",
|
||||||
"sharp": "^0.32.5",
|
"sharp": "^0.32.5",
|
||||||
|
@ -4414,6 +4416,11 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
|
||||||
|
},
|
||||||
"node_modules/client-only": {
|
"node_modules/client-only": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
|
@ -4515,6 +4522,19 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cmdk": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-dialog": "1.0.5",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||||
|
@ -4646,6 +4666,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/country-flag-icons": {
|
||||||
|
"version": "1.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.11.tgz",
|
||||||
|
"integrity": "sha512-B+mvFywunkRJs270k7kCBjhogvIA0uNn6GAXv6m2cPn3rrwqZzZVr2gBWcz+Cz7OGVWlcbERlYRIX0S6OGr8Bw=="
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
@ -6947,6 +6972,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
|
||||||
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
|
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/input-format": {
|
||||||
|
"version": "0.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/input-format/-/input-format-0.3.10.tgz",
|
||||||
|
"integrity": "sha512-5cFv/kOZD7Ch0viprVkuYPDkAU7HBZYBx8QrIpQ6yXUWbAQ0+RQ8IIojDJOf/RO6FDJLL099HDSK2KoVZ2zevg==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/internal-slot": {
|
"node_modules/internal-slot": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
|
||||||
|
@ -7572,6 +7605,11 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/libphonenumber-js": {
|
||||||
|
"version": "1.10.61",
|
||||||
|
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.61.tgz",
|
||||||
|
"integrity": "sha512-TsQsyzDttDvvzWNkbp/i0fVbzTGJIG0mUu/uNalIaRQEYeJxVQ/FPg+EJgSqfSXezREjM0V3RZ8cLVsKYhhw0Q=="
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
|
@ -13610,6 +13648,22 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-phone-number-input": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-phone-number-input/-/react-phone-number-input-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-anL8OAqlSnOXd6O+lidkprOO5+OpgW+ODrbfyLc6u8lOX8ghT0nO6ZOPrGjotpZND4cr0xxH+vu3dgbdUB2lBA==",
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.5.1",
|
||||||
|
"country-flag-icons": "^1.5.11",
|
||||||
|
"input-format": "^0.3.10",
|
||||||
|
"libphonenumber-js": "^1.10.61",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-remove-scroll": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.5.5",
|
"version": "2.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
|
"cmdk": "^1.0.0",
|
||||||
"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",
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
"react-error-boundary": "^4.0.13",
|
"react-error-boundary": "^4.0.13",
|
||||||
"react-error-overlay": "^6.0.11",
|
"react-error-overlay": "^6.0.11",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.47.0",
|
||||||
|
"react-phone-number-input": "^3.4.0",
|
||||||
"react-resizable-panels": "^2.0.16",
|
"react-resizable-panels": "^2.0.16",
|
||||||
"rehype-pretty-code": "^0.13.1",
|
"rehype-pretty-code": "^0.13.1",
|
||||||
"sharp": "^0.32.5",
|
"sharp": "^0.32.5",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { PhoneInput } from "@/components/phone-input";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
@ -58,6 +59,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
const delta = currentStep - previousStep;
|
const delta = currentStep - previousStep;
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
|
// firstname: "",
|
||||||
jobs: [
|
jobs: [
|
||||||
{
|
{
|
||||||
jobtitle: "",
|
jobtitle: "",
|
||||||
|
@ -96,7 +98,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
// console.log("product", res);
|
// console.log("product", res);
|
||||||
}
|
}
|
||||||
router.refresh();
|
router.refresh();
|
||||||
router.push(`/dashboard/products`);
|
router.push(`/dashboard`);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@ -182,8 +184,8 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const countries = [{ id: "wow", name: "india" }];
|
const countries = [{ id: "1", name: "india" }];
|
||||||
const cities = [{ id: "2", name: "kerala" }];
|
const cities = [{ id: "1", name: "kerala" }];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -307,11 +309,21 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Contact Number</FormLabel>
|
<FormLabel>Contact Number</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
{/* <Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="Enter you contact number"
|
placeholder="Enter your contact number"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
{...field}
|
{...field}
|
||||||
|
/> */}
|
||||||
|
<PhoneInput
|
||||||
|
id="phone"
|
||||||
|
// onChange={(v) => setPhone(v)}
|
||||||
|
// value={phone}
|
||||||
|
placeholder="Enter a phone number..."
|
||||||
|
defaultCountry="IN"
|
||||||
|
international
|
||||||
|
{...field}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
@ -341,7 +353,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
{countries.map((country) => (
|
{countries.map((country) => (
|
||||||
<SelectItem key={country.id} value={country.id}>
|
<SelectItem key={country.id} value={country.name.toLocaleLowerCase()}>
|
||||||
{country.name}
|
{country.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
@ -374,7 +386,7 @@ export const CreateProfileOne: React.FC<ProfileFormType> = ({
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
{cities.map((city) => (
|
{cities.map((city) => (
|
||||||
<SelectItem key={city.id} value={city.id}>
|
<SelectItem key={city.id} value={city.name.toLocaleLowerCase()}>
|
||||||
{city.name}
|
{city.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
import { CheckIcon, ChevronsUpDown } from "lucide-react";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import * as RPNInput from "react-phone-number-input";
|
||||||
|
|
||||||
|
import flags from "react-phone-number-input/flags";
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Command,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandInput,
|
||||||
|
CommandItem,
|
||||||
|
CommandList,
|
||||||
|
} from "@/components/ui/command";
|
||||||
|
import { Input, InputProps } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { ScrollArea } from "./ui/scroll-area";
|
||||||
|
|
||||||
|
type PhoneInputProps = Omit<
|
||||||
|
React.InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
"onChange" | "value"
|
||||||
|
> &
|
||||||
|
Omit<RPNInput.Props<typeof RPNInput.default>, "onChange"> & {
|
||||||
|
onChange?: (value: RPNInput.Value) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PhoneInput: React.ForwardRefExoticComponent<PhoneInputProps> =
|
||||||
|
React.forwardRef<React.ElementRef<typeof RPNInput.default>, PhoneInputProps>(
|
||||||
|
({ className, onChange, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<RPNInput.default
|
||||||
|
ref={ref}
|
||||||
|
className={cn("flex", className)}
|
||||||
|
flagComponent={FlagComponent}
|
||||||
|
countrySelectComponent={CountrySelect}
|
||||||
|
inputComponent={InputComponent}
|
||||||
|
/**
|
||||||
|
* Handles the onChange event.
|
||||||
|
*
|
||||||
|
* react-phone-number-input might trigger the onChange event as undefined
|
||||||
|
* when a valid phone number is not entered. To prevent this,
|
||||||
|
* the value is coerced to an empty string.
|
||||||
|
*
|
||||||
|
* @param {E164Number | undefined} value - The entered value
|
||||||
|
*/
|
||||||
|
onChange={(value) => onChange?.(value || "")}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
PhoneInput.displayName = "PhoneInput";
|
||||||
|
|
||||||
|
const InputComponent = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, ...props }, ref) => (
|
||||||
|
<Input
|
||||||
|
className={cn("rounded-e-lg rounded-s-none", className)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
InputComponent.displayName = "InputComponent";
|
||||||
|
|
||||||
|
type CountrySelectOption = { label: string; value: RPNInput.Country };
|
||||||
|
|
||||||
|
type CountrySelectProps = {
|
||||||
|
disabled?: boolean;
|
||||||
|
value: RPNInput.Country;
|
||||||
|
onChange: (value: RPNInput.Country) => void;
|
||||||
|
options: CountrySelectOption[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const CountrySelect = ({
|
||||||
|
disabled,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
options,
|
||||||
|
}: CountrySelectProps) => {
|
||||||
|
const handleSelect = React.useCallback(
|
||||||
|
(country: RPNInput.Country) => {
|
||||||
|
onChange(country);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant={"outline"}
|
||||||
|
className={cn("flex gap-1 rounded-e-none rounded-s-lg px-3")}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
<FlagComponent country={value} countryName={value} />
|
||||||
|
<ChevronsUpDown
|
||||||
|
className={cn(
|
||||||
|
"-mr-2 h-4 w-4 opacity-50",
|
||||||
|
disabled ? "hidden" : "opacity-100",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-[300px] p-0">
|
||||||
|
<Command>
|
||||||
|
<CommandList>
|
||||||
|
<ScrollArea className="h-72">
|
||||||
|
<CommandInput placeholder="Search country..." />
|
||||||
|
<CommandEmpty>No country found.</CommandEmpty>
|
||||||
|
<CommandGroup>
|
||||||
|
{options
|
||||||
|
.filter((x) => x.value)
|
||||||
|
.map((option) => (
|
||||||
|
<CommandItem
|
||||||
|
className="gap-2"
|
||||||
|
key={option.value}
|
||||||
|
onSelect={() => handleSelect(option.value)}
|
||||||
|
>
|
||||||
|
<FlagComponent
|
||||||
|
country={option.value}
|
||||||
|
countryName={option.label}
|
||||||
|
/>
|
||||||
|
<span className="flex-1 text-sm">{option.label}</span>
|
||||||
|
{option.value && (
|
||||||
|
<span className="text-foreground/50 text-sm">
|
||||||
|
{`+${RPNInput.getCountryCallingCode(option.value)}`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<CheckIcon
|
||||||
|
className={cn(
|
||||||
|
"ml-auto h-4 w-4",
|
||||||
|
option.value === value ? "opacity-100" : "opacity-0",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</CommandGroup>
|
||||||
|
</ScrollArea>
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FlagComponent = ({ country, countryName }: RPNInput.FlagProps) => {
|
||||||
|
const Flag = flags[country];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="bg-foreground/20 flex h-4 w-6 overflow-hidden rounded-sm">
|
||||||
|
{Flag && <Flag title={countryName} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
FlagComponent.displayName = "FlagComponent";
|
||||||
|
|
||||||
|
export { PhoneInput };
|
|
@ -59,7 +59,7 @@ const TaskPage = ({
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
console.log(isTaskPageLoading);
|
// console.log(isTaskPageLoading);
|
||||||
updateTaskPageLoading(false);
|
updateTaskPageLoading(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||||
|
import { MagnifyingGlassIcon } from "@radix-ui/react-icons"
|
||||||
|
import { Command as CommandPrimitive } from "cmdk"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||||
|
|
||||||
|
const Command = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
Command.displayName = CommandPrimitive.displayName
|
||||||
|
|
||||||
|
interface CommandDialogProps extends DialogProps {}
|
||||||
|
|
||||||
|
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||||
|
return (
|
||||||
|
<Dialog {...props}>
|
||||||
|
<DialogContent className="overflow-hidden p-0">
|
||||||
|
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||||
|
{children}
|
||||||
|
</Command>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CommandInput = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||||
|
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
<CommandPrimitive.Input
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||||
|
|
||||||
|
const CommandList = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.List>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.List
|
||||||
|
ref={ref}
|
||||||
|
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandList.displayName = CommandPrimitive.List.displayName
|
||||||
|
|
||||||
|
const CommandEmpty = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||||
|
>((props, ref) => (
|
||||||
|
<CommandPrimitive.Empty
|
||||||
|
ref={ref}
|
||||||
|
className="py-6 text-center text-sm"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||||
|
|
||||||
|
const CommandGroup = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Group
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||||
|
|
||||||
|
const CommandSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 h-px bg-border", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
const CommandItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
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",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const CommandShortcut = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CommandShortcut.displayName = "CommandShortcut"
|
||||||
|
|
||||||
|
export {
|
||||||
|
Command,
|
||||||
|
CommandDialog,
|
||||||
|
CommandInput,
|
||||||
|
CommandList,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandItem,
|
||||||
|
CommandShortcut,
|
||||||
|
CommandSeparator,
|
||||||
|
}
|
|
@ -1,29 +1,30 @@
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { isValidPhoneNumber } from "react-phone-number-input";
|
||||||
|
|
||||||
export const profileSchema = z.object({
|
export const profileSchema = z.object({
|
||||||
firstname: z
|
firstname: z
|
||||||
.string()
|
.string()
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
.min(3, { message: "First name must be at least 3 characters" }),
|
||||||
lastname: z
|
lastname: z
|
||||||
.string()
|
.string()
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
.min(3, { message: "Last name must be at least 3 characters" }),
|
||||||
email: z
|
email: z
|
||||||
.string()
|
.string()
|
||||||
.email({ message: "Product Name must be at least 3 characters" }),
|
.email({ message: "Invalid email" }),
|
||||||
contactno: z.coerce.number(),
|
contactno: z.string({required_error: "Number is required"}).refine((value) => isValidPhoneNumber(value), {message: "Invalid number"}),
|
||||||
country: z.string().min(1, { message: "Please select a category" }),
|
country: z.string().min(1, { message: "Please select a category" }),
|
||||||
city: z.string().min(1, { message: "Please select a category" }),
|
city: z.string().min(1, { message: "Please select a category" }),
|
||||||
// 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 category" }),
|
jobcountry: z.string().min(1, { message: "Please select a country" }),
|
||||||
jobcity: z.string().min(1, { message: "Please select a category" }),
|
jobcity: z.string().min(1, { message: "Please select a city" }),
|
||||||
jobtitle: z
|
jobtitle: z
|
||||||
.string()
|
.string(),
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
// .min(3, { message: "First Name must be at least 3 characters" }),
|
||||||
employer: z
|
employer: z
|
||||||
.string()
|
.string(),
|
||||||
.min(3, { message: "Product Name must be at least 3 characters" }),
|
// .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