From 8d2a2c83de4f028501eea6af771d0ee0628c9407 Mon Sep 17 00:00:00 2001 From: RizqiSyahrendra Date: Wed, 23 Apr 2025 22:47:52 +0700 Subject: [PATCH] fix: properties feature, add InputState and InputCity payload custom components --- src/app/(main)/property/[slug]/page.tsx | 8 +++- src/app/(payload)/admin/importMap.js | 4 ++ src/collections/Properties.ts | 21 +++++++---- src/components/payload-custom/InputCity.tsx | 34 +++++++++++++++++ .../payload-custom/InputCountry.tsx | 37 ------------------- src/components/payload-custom/InputState.tsx | 14 +++++++ src/components/properties/FilterProperty.tsx | 10 +++-- 7 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 src/components/payload-custom/InputCity.tsx delete mode 100644 src/components/payload-custom/InputCountry.tsx create mode 100644 src/components/payload-custom/InputState.tsx diff --git a/src/app/(main)/property/[slug]/page.tsx b/src/app/(main)/property/[slug]/page.tsx index c2e0c13..2b0a715 100644 --- a/src/app/(main)/property/[slug]/page.tsx +++ b/src/app/(main)/property/[slug]/page.tsx @@ -9,6 +9,7 @@ import FilterProperty from "@/components/properties/FilterProperty"; import { getDefaultMetadata } from "@/utils/metadata"; import { sanitizeBlogContentIntoStringPreview } from "@/utils/sanitize"; import { Metadata } from "next"; +import { State } from "country-state-city"; export async function generateMetadata(props: { params: Promise<{ slug: string }> }): Promise { const metadata = await getDefaultMetadata(); @@ -67,6 +68,9 @@ export default async function PropertyDetail({ params }: { params: Promise<{ slu if (!propertyDetail) return notFound(); const { data, formattedData } = propertyDetail; + const stateName = !!data?.addressGroup.state_code + ? State.getStateByCodeAndCountry(data.addressGroup.state_code, "US")?.name + : ""; const isEmbedMapUrlValid = !!data?.embed_map_url && data.embed_map_url.includes("www.google.com/maps/embed"); const headersList = await headers(); const fullUrl = headersList.get("x-full-url"); @@ -207,8 +211,8 @@ export default async function PropertyDetail({ params }: { params: Promise<{ slu
{data?.addressGroup?.address ?? ""}
-
State/County:
-
{data?.addressGroup?.state_code ?? ""}
+
State:
+
{stateName}
City:
diff --git a/src/app/(payload)/admin/importMap.js b/src/app/(payload)/admin/importMap.js index bbadadb..7029cc6 100644 --- a/src/app/(payload)/admin/importMap.js +++ b/src/app/(payload)/admin/importMap.js @@ -21,6 +21,8 @@ import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93 import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' +import { default as default_4ee76229d13ecca9be829e8a71d2a59d } from '../../../components/payload-custom/InputState' +import { default as default_d6f7a60d9f647737f677c5b38081a35f } from '../../../components/payload-custom/InputCity' import { default as default_aa89fa9464216e16b81a3e716c94a23a } from '../../../components/LogoAdmin' import { S3ClientUploadHandler as S3ClientUploadHandler_f97aa6c64367fa259c5bc0567239ef24 } from '@payloadcms/storage-s3/client' @@ -48,6 +50,8 @@ export const importMap = { "@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + "/components/payload-custom/InputState#default": default_4ee76229d13ecca9be829e8a71d2a59d, + "/components/payload-custom/InputCity#default": default_d6f7a60d9f647737f677c5b38081a35f, "/components/LogoAdmin#default": default_aa89fa9464216e16b81a3e716c94a23a, "@payloadcms/storage-s3/client#S3ClientUploadHandler": S3ClientUploadHandler_f97aa6c64367fa259c5bc0567239ef24 } diff --git a/src/collections/Properties.ts b/src/collections/Properties.ts index 72d34eb..1ee7a3f 100644 --- a/src/collections/Properties.ts +++ b/src/collections/Properties.ts @@ -81,18 +81,25 @@ export const Properties: CollectionConfig = { name: "state_code", label: "State", type: "text", - // admin: { - // components: { - // Field: { - // path: "/components/payload-custom/InputCountry", - // }, - // }, - // }, + admin: { + components: { + Field: { + path: "/components/payload-custom/InputState", + }, + }, + }, }, { name: "city_code", label: "City", type: "text", + admin: { + components: { + Field: { + path: "/components/payload-custom/InputCity", + }, + }, + }, }, { name: "zip_code", diff --git a/src/components/payload-custom/InputCity.tsx b/src/components/payload-custom/InputCity.tsx new file mode 100644 index 0000000..503c582 --- /dev/null +++ b/src/components/payload-custom/InputCity.tsx @@ -0,0 +1,34 @@ +"use client"; +import type { SelectFieldClientComponent } from "payload"; + +import { SelectField, useField, useFormFields } from "@payloadcms/ui"; +import { City } from "country-state-city"; +import { useEffect } from "react"; + +const InputCity: SelectFieldClientComponent = ({ field, ...props }) => { + const stateCode = useFormFields(([fields]) => fields["addressGroup.state_code"]); + const { setValue } = useField(); + + useEffect(() => { + if (!stateCode?.value) { + setValue(""); + } + }, [stateCode?.value]); + + if (!stateCode?.value) { + // @ts-ignore + field.admin = { ...field.admin, description: "Please select the state before select the city." }; + field.options = []; + } else { + // @ts-ignore + field.admin = { ...field.admin, description: "" }; + field.options = City.getCitiesOfState("US", stateCode.value as string).map((c) => ({ + value: c.name, + label: c.name, + })); + } + + return ; +}; + +export default InputCity; diff --git a/src/components/payload-custom/InputCountry.tsx b/src/components/payload-custom/InputCountry.tsx deleted file mode 100644 index b56d7b2..0000000 --- a/src/components/payload-custom/InputCountry.tsx +++ /dev/null @@ -1,37 +0,0 @@ -"use client"; -import React from "react"; -import { useField } from "@payloadcms/ui"; -import { TextFieldClientComponent } from "payload"; - -const InputCountry: TextFieldClientComponent = ({ path, field }) => { - const { value, setValue } = useField({ path }); - const { showError } = useField(); - - return ( -
- {/* @ts-ignore */} - jancok - {/* */} -
- -
- {/* {field.admin && } - {showError && } */} -
- ); -}; - -export default InputCountry; diff --git a/src/components/payload-custom/InputState.tsx b/src/components/payload-custom/InputState.tsx new file mode 100644 index 0000000..e0174bf --- /dev/null +++ b/src/components/payload-custom/InputState.tsx @@ -0,0 +1,14 @@ +"use client"; +import type { SelectFieldClientComponent } from "payload"; + +import { SelectField } from "@payloadcms/ui"; +import React from "react"; +import { State } from "country-state-city"; + +const InputState: SelectFieldClientComponent = ({ field, ...props }) => { + const statesData = State.getStatesOfCountry("US").map((st) => ({ value: st.isoCode, label: st.name })); + field.options = statesData; + return ; +}; + +export default InputState; diff --git a/src/components/properties/FilterProperty.tsx b/src/components/properties/FilterProperty.tsx index e2ce402..33cafdb 100644 --- a/src/components/properties/FilterProperty.tsx +++ b/src/components/properties/FilterProperty.tsx @@ -10,7 +10,10 @@ type FilterPropertyProps = { }; export default function FilterProperty({ propertyType, searchParams }: FilterPropertyProps) { - const statesData = State.getStatesOfCountry("US").map((st) => ({ value: st.name, label: st.name })); + const statesData = State.getStatesOfCountry("US").map((st) => ({ value: st.isoCode, label: st.name })); + const selectedStateName = !!searchParams?.location + ? State.getStateByCodeAndCountry(searchParams.location, "US")?.name + : ""; return ( <> @@ -25,8 +28,9 @@ export default function FilterProperty({ propertyType, searchParams }: FilterPro name="location" placeholder="Choose Location" options={statesData} - defaultInputValue={searchParams?.location} - defaultValue={searchParams?.location} + defaultValue={ + !!searchParams?.location ? { value: searchParams?.location, label: selectedStateName } : undefined + } isSearchable isClearable />