diff --git a/package.json b/package.json
index 66b26e6..c2f98df 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"@payloadcms/payload-cloud": "^3.35.1",
"@payloadcms/richtext-lexical": "^3.35.1",
"@payloadcms/storage-s3": "^3.35.1",
+ "country-state-city": "^3.2.1",
"dayjs": "^1.11.13",
"graphql": "^16.8.1",
"next": "15.3.0",
diff --git a/src/app/(main)/listings-for-rent/page.tsx b/src/app/(main)/listings-for-rent/page.tsx
index 107775c..ead755e 100644
--- a/src/app/(main)/listings-for-rent/page.tsx
+++ b/src/app/(main)/listings-for-rent/page.tsx
@@ -3,6 +3,7 @@ import HeroImage from "@/components/HeroImage";
import Pagination from "@/components/Pagination";
import { CardPropertyData } from "@/schema/property";
import { getDefaultMetadata } from "@/utils/metadata";
+import { Country, State } from "country-state-city";
import { Metadata } from "next";
const metaDesc = "Explore the latest properties on the Dynamic Realty.";
@@ -75,6 +76,9 @@ const propertiesData: CardPropertyData[] = [
];
export default function ListingsForRent() {
+ // const countries = State.getStatesOfCountry("ID");
+ // console.log(countries);
+
return (
<>
diff --git a/src/collections/Properties.ts b/src/collections/Properties.ts
new file mode 100644
index 0000000..e20de77
--- /dev/null
+++ b/src/collections/Properties.ts
@@ -0,0 +1,140 @@
+import formatSlug from "@/utils/payload/formatSlug";
+import type { CollectionConfig } from "payload";
+
+export const Properties: CollectionConfig = {
+ slug: "properties",
+ labels: { plural: "Properties", singular: "Property" },
+ fields: [
+ {
+ name: "name",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "slug",
+ type: "text",
+ admin: {
+ position: "sidebar",
+ },
+ hooks: {
+ beforeValidate: [formatSlug("name")],
+ },
+ },
+ {
+ name: "images",
+ type: "relationship",
+ relationTo: "media",
+ hasMany: true,
+ minRows: 1,
+ required: true,
+ },
+ {
+ name: "aboutGroup",
+ label: "About",
+ type: "group",
+ fields: [
+ {
+ name: "description",
+ type: "richText",
+ required: true,
+ },
+ {
+ name: "area",
+ label: "Area (Sqft)",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "bathrooms_count",
+ label: "Total Bathrooms",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "bedrooms_count",
+ label: "Total Bedrooms",
+ type: "text",
+ required: true,
+ },
+ ],
+ },
+ {
+ name: "addressGroup",
+ label: "Address",
+ type: "group",
+ fields: [
+ {
+ name: "country_code",
+ label: "Country",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "state_code",
+ label: "State",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "city_code",
+ label: "City",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "zip_code",
+ label: "Zip",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "address",
+ label: "Address",
+ type: "text",
+ required: true,
+ },
+ ],
+ },
+ {
+ name: "features",
+ type: "relationship",
+ relationTo: "propertyFeatures",
+ required: true,
+ hasMany: true,
+ minRows: 1,
+ },
+ {
+ name: "base_price",
+ label: "Base Price",
+ type: "number",
+ required: true,
+ },
+ {
+ name: "additional_price",
+ label: "Additional Price",
+ type: "array",
+ fields: [
+ {
+ name: "name",
+ type: "text",
+ required: true,
+ },
+ {
+ name: "price",
+ type: "number",
+ required: true,
+ },
+ ],
+ },
+ {
+ name: "embed_map_url",
+ label: "Embed Map URL",
+ type: "text",
+ },
+ ],
+ admin: {
+ hideAPIURL: true,
+ group: "Properties",
+ useAsTitle: "name",
+ },
+};
diff --git a/src/collections/PropertyFeatures.ts b/src/collections/PropertyFeatures.ts
new file mode 100644
index 0000000..2e3fef8
--- /dev/null
+++ b/src/collections/PropertyFeatures.ts
@@ -0,0 +1,18 @@
+import type { CollectionConfig } from "payload";
+
+export const PropertyFeatures: CollectionConfig = {
+ slug: "propertyFeatures",
+ labels: { plural: "Property Features", singular: "Property Feature" },
+ fields: [
+ {
+ name: "name",
+ type: "text",
+ required: true,
+ },
+ ],
+ admin: {
+ hideAPIURL: true,
+ group: "Properties",
+ useAsTitle: "name",
+ },
+};
diff --git a/src/payload-types.ts b/src/payload-types.ts
index 6ea9a7e..c56a86d 100644
--- a/src/payload-types.ts
+++ b/src/payload-types.ts
@@ -72,6 +72,8 @@ export interface Config {
blogTags: BlogTag;
blogCategories: BlogCategory;
blogs: Blog;
+ propertyFeatures: PropertyFeature;
+ properties: Property;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
@@ -83,6 +85,8 @@ export interface Config {
blogTags: BlogTagsSelect | BlogTagsSelect;
blogCategories: BlogCategoriesSelect | BlogCategoriesSelect;
blogs: BlogsSelect | BlogsSelect;
+ propertyFeatures: PropertyFeaturesSelect | PropertyFeaturesSelect;
+ properties: PropertiesSelect | PropertiesSelect;
'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect;
'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect;
'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect;
@@ -219,6 +223,65 @@ export interface Blog {
createdAt: string;
_status?: ('draft' | 'published') | null;
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "propertyFeatures".
+ */
+export interface PropertyFeature {
+ id: number;
+ name: string;
+ updatedAt: string;
+ createdAt: string;
+}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "properties".
+ */
+export interface Property {
+ id: number;
+ name: string;
+ slug?: string | null;
+ images: (number | Media)[];
+ aboutGroup: {
+ description: {
+ root: {
+ type: string;
+ children: {
+ type: string;
+ version: number;
+ [k: string]: unknown;
+ }[];
+ direction: ('ltr' | 'rtl') | null;
+ format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
+ indent: number;
+ version: number;
+ };
+ [k: string]: unknown;
+ };
+ area: string;
+ bathrooms_count: string;
+ bedrooms_count: string;
+ };
+ addressGroup: {
+ country_code: string;
+ state_code: string;
+ city_code: string;
+ zip_code: string;
+ address: string;
+ };
+ features: (number | PropertyFeature)[];
+ base_price: number;
+ additional_price?:
+ | {
+ name: string;
+ price: number;
+ id?: string | null;
+ }[]
+ | null;
+ embed_map_url?: string | null;
+ updatedAt: string;
+ createdAt: string;
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
@@ -245,6 +308,14 @@ export interface PayloadLockedDocument {
| ({
relationTo: 'blogs';
value: number | Blog;
+ } | null)
+ | ({
+ relationTo: 'propertyFeatures';
+ value: number | PropertyFeature;
+ } | null)
+ | ({
+ relationTo: 'properties';
+ value: number | Property;
} | null);
globalSlug?: string | null;
user: {
@@ -370,6 +441,53 @@ export interface BlogsSelect {
createdAt?: T;
_status?: T;
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "propertyFeatures_select".
+ */
+export interface PropertyFeaturesSelect {
+ name?: T;
+ updatedAt?: T;
+ createdAt?: T;
+}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "properties_select".
+ */
+export interface PropertiesSelect {
+ name?: T;
+ slug?: T;
+ images?: T;
+ aboutGroup?:
+ | T
+ | {
+ description?: T;
+ area?: T;
+ bathrooms_count?: T;
+ bedrooms_count?: T;
+ };
+ addressGroup?:
+ | T
+ | {
+ country_code?: T;
+ state_code?: T;
+ city_code?: T;
+ zip_code?: T;
+ address?: T;
+ };
+ features?: T;
+ base_price?: T;
+ additional_price?:
+ | T
+ | {
+ name?: T;
+ price?: T;
+ id?: T;
+ };
+ embed_map_url?: T;
+ updatedAt?: T;
+ createdAt?: T;
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
diff --git a/src/payload.config.ts b/src/payload.config.ts
index 83618ec..9d87b61 100644
--- a/src/payload.config.ts
+++ b/src/payload.config.ts
@@ -13,6 +13,8 @@ import { Media } from "@/collections/Media";
import { BlogTags } from "@/collections/BlogTags";
import { BlogCategories } from "@/collections/BlogCategories";
import { Blogs } from "@/collections/Blogs";
+import { PropertyFeatures } from "@/collections/PropertyFeatures";
+import { Properties } from "./collections/Properties";
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
@@ -37,7 +39,7 @@ export default buildConfig({
},
theme: "dark",
},
- collections: [Users, Media, BlogTags, BlogCategories, Blogs],
+ collections: [Users, Media, BlogTags, BlogCategories, Blogs, PropertyFeatures, Properties],
editor: lexicalEditor(),
secret: process.env.PAYLOAD_SECRET || "",
typescript: {
diff --git a/yarn.lock b/yarn.lock
index 7579afd..e7a4fbd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4652,6 +4652,13 @@ __metadata:
languageName: node
linkType: hard
+"country-state-city@npm:^3.2.1":
+ version: 3.2.1
+ resolution: "country-state-city@npm:3.2.1"
+ checksum: 10c0/2545a000c207345514de31c20ed8a331bba9796f36ab1e6e4019ebb319bca37894180e4ade40eef9d7f2443aa60045ec3f317bfdb3f4c7b99b9c711e4688d8cb
+ languageName: node
+ linkType: hard
+
"croner@npm:9.0.0":
version: 9.0.0
resolution: "croner@npm:9.0.0"
@@ -5022,6 +5029,7 @@ __metadata:
"@types/node": "npm:^20"
"@types/react": "npm:^19"
"@types/react-dom": "npm:^19"
+ country-state-city: "npm:^3.2.1"
dayjs: "npm:^1.11.13"
eslint: "npm:^9"
eslint-config-next: "npm:15.3.0"