Improved the Country selector
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
"axios": "^1.3.5",
|
"axios": "^1.3.5",
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
|
"countries-list": "^3.0.1",
|
||||||
"country-codes-list": "^1.6.11",
|
"country-codes-list": "^1.6.11",
|
||||||
"daisyui": "^3.1.5",
|
"daisyui": "^3.1.5",
|
||||||
"eslint": "8.33.0",
|
"eslint": "8.33.0",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {BsArrowRepeat} from "react-icons/bs";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {toast} from "react-toastify";
|
import {toast} from "react-toastify";
|
||||||
import {KeyedMutator} from "swr";
|
import {KeyedMutator} from "swr";
|
||||||
|
import CountrySelect from "./Low/CountrySelect";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
mutateUser: KeyedMutator<User>;
|
mutateUser: KeyedMutator<User>;
|
||||||
@@ -54,22 +55,7 @@ export default function DemographicInformationInput({mutateUser}: Props) {
|
|||||||
<form className="flex flex-col items-center justify-items-center gap-6 w-full h-full -lg:px-8 lg:w-1/2 mb-32" onSubmit={save}>
|
<form className="flex flex-col items-center justify-items-center gap-6 w-full h-full -lg:px-8 lg:w-1/2 mb-32" onSubmit={save}>
|
||||||
<div className="relative flex flex-col gap-3 w-full">
|
<div className="relative flex flex-col gap-3 w-full">
|
||||||
<label className="font-normal text-base text-mti-gray-dim">Country *</label>
|
<label className="font-normal text-base text-mti-gray-dim">Country *</label>
|
||||||
<select
|
<CountrySelect value={country} onChange={setCountry} />
|
||||||
name="country"
|
|
||||||
className="px-8 py-6 text-sm font-normal placeholder:text-mti-gray-cool bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
|
|
||||||
onChange={(e) => {
|
|
||||||
setCountry(e.target.value);
|
|
||||||
}}
|
|
||||||
defaultValue={country}>
|
|
||||||
<option value={undefined} disabled selected>
|
|
||||||
Select a country
|
|
||||||
</option>
|
|
||||||
{countryCodes.all().map((x) => (
|
|
||||||
<option key={x.countryCode} value={x.countryCode}>
|
|
||||||
{x.flag} {x.countryNameLocal}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<Input type="tel" name="phone" label="Phone number" onChange={(e) => setPhone(e)} placeholder="Enter phone number" required />
|
<Input type="tel" name="phone" label="Phone number" onChange={(e) => setPhone(e)} placeholder="Enter phone number" required />
|
||||||
<div className="relative flex flex-col gap-3 w-full">
|
<div className="relative flex flex-col gap-3 w-full">
|
||||||
|
|||||||
73
src/components/Low/CountrySelect.tsx
Normal file
73
src/components/Low/CountrySelect.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import {countries, TCountries} from "countries-list";
|
||||||
|
import {Fragment, useState} from "react";
|
||||||
|
import {Combobox, Transition} from "@headlessui/react";
|
||||||
|
import {BsChevronExpand} from "react-icons/bs";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value?: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapCountries = (codes: string[]) => {
|
||||||
|
return codes.map((code) => ({
|
||||||
|
label: countries[code as unknown as keyof TCountries].name,
|
||||||
|
code,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CountrySelect({value, onChange}: Props) {
|
||||||
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
|
const filteredCountries =
|
||||||
|
query === ""
|
||||||
|
? mapCountries(Object.keys(countries))
|
||||||
|
: mapCountries(
|
||||||
|
Object.keys(countries).filter((x) =>
|
||||||
|
countries[x as unknown as keyof TCountries].name.toLowerCase().includes(query.toLowerCase()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Combobox value={value} onChange={onChange}>
|
||||||
|
<div className="relative mt-1">
|
||||||
|
<div className="relative w-full cursor-default overflow-hidden ">
|
||||||
|
<Combobox.Input
|
||||||
|
className="py-6 w-full px-8 text-sm font-normal placeholder:text-mti-gray-cool bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
displayValue={(code: string) => countries[code as unknown as keyof TCountries].name}
|
||||||
|
/>
|
||||||
|
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-8">
|
||||||
|
<BsChevronExpand />
|
||||||
|
</Combobox.Button>
|
||||||
|
</div>
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
leave="transition ease-in duration-100"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
afterLeave={() => setQuery("")}>
|
||||||
|
<Combobox.Options className="absolute z-20 mt-1 max-h-60 w-full overflow-auto rounded-xl bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||||
|
{filteredCountries.length === 0 && query !== "" ? (
|
||||||
|
<div className="relative cursor-default select-none py-2 px-4 text-gray-700">Nothing found.</div>
|
||||||
|
) : (
|
||||||
|
filteredCountries.map((country) => (
|
||||||
|
<Combobox.Option
|
||||||
|
key={country.code}
|
||||||
|
value={country.code}
|
||||||
|
className={({active}) =>
|
||||||
|
`relative cursor-default select-none py-2 pl-10 pr-4 ${
|
||||||
|
active ? "bg-mti-purple-light text-white" : "text-gray-900"
|
||||||
|
}`
|
||||||
|
}>
|
||||||
|
{country.label}
|
||||||
|
</Combobox.Option>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</Combobox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ import {RadioGroup} from "@headlessui/react";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {EmploymentStatus, EMPLOYMENT_STATUS, Gender, User} from "@/interfaces/user";
|
import {EmploymentStatus, EMPLOYMENT_STATUS, Gender, User} from "@/interfaces/user";
|
||||||
import countryCodes from "country-codes-list";
|
import countryCodes from "country-codes-list";
|
||||||
|
import {countries, TCountries} from "countries-list";
|
||||||
|
import CountrySelect from "@/components/Low/CountrySelect";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
@@ -186,22 +188,7 @@ export default function Home() {
|
|||||||
<div className="flex flex-row gap-8 w-full">
|
<div className="flex flex-row gap-8 w-full">
|
||||||
<div className="flex flex-col gap-3 w-full">
|
<div className="flex flex-col gap-3 w-full">
|
||||||
<label className="font-normal text-base text-mti-gray-dim">Country *</label>
|
<label className="font-normal text-base text-mti-gray-dim">Country *</label>
|
||||||
<select
|
<CountrySelect value={country} onChange={setCountry} />
|
||||||
name="country"
|
|
||||||
className="py-6 w-full px-8 text-sm font-normal placeholder:text-mti-gray-cool bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
|
|
||||||
onChange={(e) => {
|
|
||||||
setCountry(e.target.value);
|
|
||||||
}}
|
|
||||||
value={country}>
|
|
||||||
<option value={undefined} disabled selected>
|
|
||||||
Select a country
|
|
||||||
</option>
|
|
||||||
{countryCodes.all().map((x) => (
|
|
||||||
<option key={x.countryCode} value={x.countryCode}>
|
|
||||||
{x.flag} {x.countryNameLocal}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
type="tel"
|
type="tel"
|
||||||
|
|||||||
@@ -1318,6 +1318,11 @@ cookie@^0.5.0:
|
|||||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
|
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
|
||||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||||
|
|
||||||
|
countries-list@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/countries-list/-/countries-list-3.0.1.tgz#1aa25be6611c56e39b458a25ba22d2b6ff0623e4"
|
||||||
|
integrity sha512-SKsTld6jDTHVGGEg6/1FEQXMJ7EeAFWFq2u+flrvdIeb19BYtNwnqvfaCvutQv3Yb9B44Wfhly4WXNBePIaCuA==
|
||||||
|
|
||||||
country-codes-list@^1.6.11:
|
country-codes-list@^1.6.11:
|
||||||
version "1.6.11"
|
version "1.6.11"
|
||||||
resolved "https://registry.yarnpkg.com/country-codes-list/-/country-codes-list-1.6.11.tgz#fd8241c9a833447677a1b8efdd0e1cd19a1fc176"
|
resolved "https://registry.yarnpkg.com/country-codes-list/-/country-codes-list-1.6.11.tgz#fd8241c9a833447677a1b8efdd0e1cd19a1fc176"
|
||||||
|
|||||||
Reference in New Issue
Block a user