feat(projects): دادههای واقعی پروژهها — ستونهای تازه و حذف دادههای ماک
- دیتابیس/مدل/اسکیما: land_area (مساحت عرصه)، pilot_floors (طبقات روی همکف/پیلوت) و سه ستون واحدها (مسکونی/تجاری/اداری) بهجای «واحدها»ی تکی - فایل استاتیک projectsData (دادههای ماک) حذف شد؛ لیست، جزئیات و «پروژههای شاخص» همه از دیتابیس میخوانند - برچسبهای i18n فهرست مشخصات مطابق شیت تیم
This commit is contained in:
@@ -27,7 +27,11 @@ EN_COLUMNS: list[tuple[str, str, str]] = [
|
|||||||
("projects", "year_en", "VARCHAR(64)"),
|
("projects", "year_en", "VARCHAR(64)"),
|
||||||
("projects", "area_en", "VARCHAR(64)"),
|
("projects", "area_en", "VARCHAR(64)"),
|
||||||
("projects", "floors_en", "VARCHAR(64)"),
|
("projects", "floors_en", "VARCHAR(64)"),
|
||||||
("projects", "units_en", "VARCHAR(64)"),
|
("projects", "land_area", "VARCHAR(64)"),
|
||||||
|
("projects", "pilot_floors", "VARCHAR(32)"),
|
||||||
|
("projects", "units_residential", "VARCHAR(32)"),
|
||||||
|
("projects", "units_commercial", "VARCHAR(32)"),
|
||||||
|
("projects", "units_office", "VARCHAR(32)"),
|
||||||
("projects", "client_en", "VARCHAR(128)"),
|
("projects", "client_en", "VARCHAR(128)"),
|
||||||
("projects", "project_type", "VARCHAR(128)"),
|
("projects", "project_type", "VARCHAR(128)"),
|
||||||
("projects", "project_type_en", "VARCHAR(128)"),
|
("projects", "project_type_en", "VARCHAR(128)"),
|
||||||
|
|||||||
@@ -72,8 +72,11 @@ class Project(Base):
|
|||||||
area_en: Mapped[str] = mapped_column(String(64), default="")
|
area_en: Mapped[str] = mapped_column(String(64), default="")
|
||||||
floors: Mapped[str] = mapped_column(String(64), default="")
|
floors: Mapped[str] = mapped_column(String(64), default="")
|
||||||
floors_en: Mapped[str] = mapped_column(String(64), default="")
|
floors_en: Mapped[str] = mapped_column(String(64), default="")
|
||||||
units: Mapped[str] = mapped_column(String(64), default="")
|
land_area: Mapped[str] = mapped_column(String(64), default="")
|
||||||
units_en: Mapped[str] = mapped_column(String(64), default="")
|
pilot_floors: Mapped[str] = mapped_column(String(32), default="")
|
||||||
|
units_residential: Mapped[str] = mapped_column(String(32), default="")
|
||||||
|
units_commercial: Mapped[str] = mapped_column(String(32), default="")
|
||||||
|
units_office: Mapped[str] = mapped_column(String(32), default="")
|
||||||
client: Mapped[str] = mapped_column(String(128), default="")
|
client: Mapped[str] = mapped_column(String(128), default="")
|
||||||
client_en: Mapped[str] = mapped_column(String(128), default="")
|
client_en: Mapped[str] = mapped_column(String(128), default="")
|
||||||
# مشخصات تکمیلی پروژه — به درخواست تیم: نوع پروژه و کاربری
|
# مشخصات تکمیلی پروژه — به درخواست تیم: نوع پروژه و کاربری
|
||||||
|
|||||||
+10
-4
@@ -57,8 +57,11 @@ class ProjectOut(ORMModel):
|
|||||||
area_en: str = ""
|
area_en: str = ""
|
||||||
floors: str
|
floors: str
|
||||||
floors_en: str = ""
|
floors_en: str = ""
|
||||||
units: str
|
land_area: str = ""
|
||||||
units_en: str = ""
|
pilot_floors: str = ""
|
||||||
|
units_residential: str = ""
|
||||||
|
units_commercial: str = ""
|
||||||
|
units_office: str = ""
|
||||||
client: str
|
client: str
|
||||||
client_en: str = ""
|
client_en: str = ""
|
||||||
project_type: str = ""
|
project_type: str = ""
|
||||||
@@ -455,6 +458,11 @@ class ProjectIn(BaseModel):
|
|||||||
year: str = ""
|
year: str = ""
|
||||||
year_en: str = ""
|
year_en: str = ""
|
||||||
status: Literal["done", "progress"] = "done"
|
status: Literal["done", "progress"] = "done"
|
||||||
|
land_area: str = ""
|
||||||
|
pilot_floors: str = ""
|
||||||
|
units_residential: str = ""
|
||||||
|
units_commercial: str = ""
|
||||||
|
units_office: str = ""
|
||||||
project_type: str = ""
|
project_type: str = ""
|
||||||
project_type_en: str = ""
|
project_type_en: str = ""
|
||||||
usage: str = ""
|
usage: str = ""
|
||||||
@@ -465,8 +473,6 @@ class ProjectIn(BaseModel):
|
|||||||
area_en: str = ""
|
area_en: str = ""
|
||||||
floors: str = ""
|
floors: str = ""
|
||||||
floors_en: str = ""
|
floors_en: str = ""
|
||||||
units: str = ""
|
|
||||||
units_en: str = ""
|
|
||||||
client: str = ""
|
client: str = ""
|
||||||
client_en: str = ""
|
client_en: str = ""
|
||||||
summary: str = ""
|
summary: str = ""
|
||||||
|
|||||||
@@ -69,8 +69,10 @@ export const ENTITIES: Record<string, EntityConfig> = {
|
|||||||
F('title', 'عنوان'), F('slug', 'نشانی (slug)', 'text', undefined, true), F('location', 'موقعیت'),
|
F('title', 'عنوان'), F('slug', 'نشانی (slug)', 'text', undefined, true), F('location', 'موقعیت'),
|
||||||
F('year', 'سال'), F('status', 'وضعیت', 'text', 'done یا progress', true),
|
F('year', 'سال'), F('status', 'وضعیت', 'text', 'done یا progress', true),
|
||||||
F('image', 'تصویر شاخص', 'image', undefined, true), F('gallery', 'گالری (هر خط یک URL)', 'list', undefined, true),
|
F('image', 'تصویر شاخص', 'image', undefined, true), F('gallery', 'گالری (هر خط یک URL)', 'list', undefined, true),
|
||||||
F('area', 'زیربنا'), F('floors', 'طبقات'), F('units', 'واحدها'),
|
F('land_area', 'مساحت عرصه (زمین)'), F('area', 'مساحت زیربنا (اعیان)'),
|
||||||
F('project_type', 'نوع پروژه'), F('usage', 'کاربری'), F('client', 'کارفرما'),
|
F('usage', 'کاربری ساختمان'), F('pilot_floors', 'طبقات روی همکف (پیلوت)'), F('floors', 'تعداد طبقات'),
|
||||||
|
F('units_residential', 'تعداد واحد مسکونی'), F('units_commercial', 'تعداد واحد تجاری'), F('units_office', 'تعداد واحد اداری'),
|
||||||
|
F('project_type', 'نوع پروژه'),
|
||||||
F('summary', 'خلاصه', 'textarea'), F('body', 'متن پروژه (هر پاراگراف یک خط)', 'list'),
|
F('summary', 'خلاصه', 'textarea'), F('body', 'متن پروژه (هر پاراگراف یک خط)', 'list'),
|
||||||
],
|
],
|
||||||
defaults: { title: 'پروژه جدید', slug: `project-${Date.now()}`, location: '', year: '', status: 'done', image: '', gallery: [], area: '', floors: '', units: '', client: '', summary: '', body: [] },
|
defaults: { title: 'پروژه جدید', slug: `project-${Date.now()}`, location: '', year: '', status: 'done', image: '', gallery: [], area: '', floors: '', units: '', client: '', summary: '', body: [] },
|
||||||
|
|||||||
@@ -2,7 +2,14 @@ import { Link } from 'react-router-dom'
|
|||||||
import { useStatusLabel } from '../api'
|
import { useStatusLabel } from '../api'
|
||||||
import { useLang } from '../i18n/lang'
|
import { useLang } from '../i18n/lang'
|
||||||
import { PremiumButton } from './PremiumButton'
|
import { PremiumButton } from './PremiumButton'
|
||||||
import type { StaticProject } from '../data/projectsData'
|
export type StaticProject = {
|
||||||
|
id: string
|
||||||
|
slug: string
|
||||||
|
name: { en: string; fa: string }
|
||||||
|
location: { en: string; fa: string }
|
||||||
|
area: { en: string; fa: string }
|
||||||
|
status: 'done' | 'progress'
|
||||||
|
}
|
||||||
import type { ProjectCardItem } from '../data/site'
|
import type { ProjectCardItem } from '../data/site'
|
||||||
|
|
||||||
type ProjectCardProps = {
|
type ProjectCardProps = {
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ import { useFieldSaver } from '../../admin/AdminContext'
|
|||||||
import { useLang } from '../../i18n/lang'
|
import { useLang } from '../../i18n/lang'
|
||||||
import { InlineEdit } from '../admin/InlineEdit'
|
import { InlineEdit } from '../admin/InlineEdit'
|
||||||
import type { ProjectStatus } from '../../data/site'
|
import type { ProjectStatus } from '../../data/site'
|
||||||
import { projectsData } from '../../data/projectsData'
|
|
||||||
|
|
||||||
export function FeaturedProjects() {
|
export function FeaturedProjects() {
|
||||||
const { status_labels } = useSite()
|
const { status_labels, projects } = useSite()
|
||||||
const { t, href } = useLang()
|
const { t, href } = useLang()
|
||||||
const heading = useSectionHeading('featured_projects')
|
const heading = useSectionHeading('featured_projects')
|
||||||
const save = useFieldSaver()
|
const save = useFieldSaver()
|
||||||
@@ -34,8 +33,8 @@ export function FeaturedProjects() {
|
|||||||
|
|
||||||
const [status, setStatus] = useState<ProjectStatus>('done')
|
const [status, setStatus] = useState<ProjectStatus>('done')
|
||||||
|
|
||||||
// Filter and slice static project data
|
// سه پروژه از دیتابیس — ویرایش پنل همانجا اعمال میشود
|
||||||
const list = projectsData.filter((p) => p.status === status).slice(0, 3)
|
const list = projects.filter((p) => p.status === status).slice(0, 3)
|
||||||
const BASE_IMG_URL = "/seed-media/2026/09/";
|
const BASE_IMG_URL = "/seed-media/2026/09/";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -87,8 +86,7 @@ export function FeaturedProjects() {
|
|||||||
className="grid gap-6 lg:grid-cols-3"
|
className="grid gap-6 lg:grid-cols-3"
|
||||||
>
|
>
|
||||||
{list.map((project, i) => {
|
{list.map((project, i) => {
|
||||||
const dummyImageName = `${(i % 6) + 1}.png`;
|
const imageUrl = project.image || undefined;
|
||||||
const imageUrl = `${BASE_IMG_URL}${dummyImageName}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
export type BilingualText = { en: string; fa: string };
|
|
||||||
|
|
||||||
export type StaticProject = {
|
|
||||||
id: string;
|
|
||||||
slug: string;
|
|
||||||
name: BilingualText;
|
|
||||||
location: BilingualText;
|
|
||||||
area: BilingualText;
|
|
||||||
status: 'done' | 'progress';
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const projectsData: StaticProject[] = [
|
|
||||||
{ id: '1', slug: 'project-1', name: { en: 'Project 1', fa: 'پروژه سروش' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '2', slug: 'project-2', name: { en: 'Project 2', fa: 'چهرازی-زیتون' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '3', slug: 'project-3', name: { en: 'Project 3', fa: 'جعفریان' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '4', slug: 'project-4', name: { en: 'Project 4', fa: 'بهار' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '5', slug: 'project-5', name: { en: 'Project 5', fa: 'حسن مرادی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '6', slug: 'project-6', name: { en: 'Project 6', fa: 'کوثر' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '7', slug: 'project-7', name: { en: 'Project 7', fa: 'صبا' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '8', slug: 'project-8', name: { en: 'Project 8', fa: 'پورمعالی - بهشت' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '9', slug: 'project-9', name: { en: 'Project 9', fa: '2 پروژه- فردوس' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '10', slug: 'project-10', name: { en: 'Project 10', fa: 'ارم' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '11', slug: 'project-11', name: { en: 'Project 11', fa: 'سینا' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '12', slug: 'project-12', name: { en: 'Project 12', fa: 'مسجد سید' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '13', slug: 'project-13', name: { en: 'Project 13', fa: 'هفده شهریور' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '14', slug: 'project-14', name: { en: 'Project 14', fa: 'آرامش رفیع زاده' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '15', slug: 'project-15', name: { en: 'Project 15', fa: 'بن بست شریعت' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '16', slug: 'project-16', name: { en: 'Project 16', fa: 'قصر - یاسین' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '17', slug: 'project-17', name: { en: 'Project 17', fa: 'پردیس' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '18', slug: 'project-18', name: { en: 'Project 18', fa: 'آرامش حکیم' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '19', slug: 'project-19', name: { en: 'Project 19', fa: 'آرامش دخانیات' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '20', slug: 'project-20', name: { en: 'Project 20', fa: 'بهشتی فرشادی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '21', slug: 'project-21', name: { en: 'Project 21', fa: 'کاکتوس' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '22', slug: 'project-22', name: { en: 'Project 22', fa: 'آرامش - صیاد' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '23', slug: 'project-23', name: { en: 'Project 23', fa: 'کوثر' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '24', slug: 'project-24', name: { en: 'Project 24', fa: 'آرامش - بوعلی 1' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '25', slug: 'project-25', name: { en: 'Project 25', fa: 'میرزا نصیر' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '26', slug: 'project-26', name: { en: 'Project 26', fa: 'نیکان' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '27', slug: 'project-27', name: { en: 'Project 27', fa: 'آرامش-رسا' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '28', slug: 'project-28', name: { en: 'Project 28', fa: 'نگین' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '29', slug: 'project-29', name: { en: 'Project 29', fa: 'آرامش - بوعلی 2' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '30', slug: 'project-30', name: { en: 'Project 30', fa: 'آرامش استاد همایی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '31', slug: 'project-31', name: { en: 'Project 31', fa: 'آرامش صدر' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '32', slug: 'project-32', name: { en: 'Project 32', fa: 'آرامش - سپهسالار' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '33', slug: 'project-33', name: { en: 'Project 33', fa: 'آرامش- صدر' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '34', slug: 'project-34', name: { en: 'Project 34', fa: 'آرامش - سنایی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '35', slug: 'project-35', name: { en: 'Project 35', fa: 'مغازه لباس فروشی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '36', slug: 'project-36', name: { en: 'Project 36', fa: 'آرامش - آتشگاه' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '37', slug: 'project-37', name: { en: 'Project 37', fa: 'آرامش - بزرگمهر' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '38', slug: 'project-38', name: { en: 'Project 38', fa: 'آرامش - سعدی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '39', slug: 'project-39', name: { en: 'Project 39', fa: 'آرامش - صمدیه لباف' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '40', slug: 'project-40', name: { en: 'Project 40', fa: 'آرامش 2' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '41', slug: 'project-41', name: { en: 'Project 41', fa: 'آرامش 5 رمضان' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '42', slug: 'project-42', name: { en: 'Project 42', fa: 'آرامش احمدآباد' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '43', slug: 'project-43', name: { en: 'Project 43', fa: 'تجاری آتشگاه' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '44', slug: 'project-44', name: { en: 'Project 44', fa: 'آرامش - شهیدان' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '45', slug: 'project-45', name: { en: 'Project 45', fa: 'آرامش خواجو' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '46', slug: 'project-46', name: { en: 'Project 46', fa: 'آرامش- اداری ابوالحسن' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '47', slug: 'project-47', name: { en: 'Project 47', fa: 'آرامش - انقلاب' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '48', slug: 'project-48', name: { en: 'Project 48', fa: 'آرامش - شریف' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '49', slug: 'project-49', name: { en: 'Project 49', fa: 'آرامش - کهندژ' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '50', slug: 'project-50', name: { en: 'Project 50', fa: 'آرامش جی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '51', slug: 'project-51', name: { en: 'Project 51', fa: 'آرامش - بابک' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '52', slug: 'project-52', name: { en: 'Project 52', fa: 'آرامش - شمس آبادی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '53', slug: 'project-53', name: { en: 'Project 53', fa: 'آرامش - میرزاطاهر 3' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '54', slug: 'project-54', name: { en: 'Project 54', fa: 'آرامش - وحدت' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '55', slug: 'project-55', name: { en: 'Project 55', fa: 'آرامش پروین' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'done' },
|
|
||||||
{ id: '56', slug: 'project-56', name: { en: 'Project 56', fa: 'خلیفه سلطانی' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '57', slug: 'project-57', name: { en: 'Project 57', fa: 'آرامش - میرزا طاهر 5' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '58', slug: 'project-58', name: { en: 'Project 58', fa: 'آرامش - میرزاطاهر 6' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '59', slug: 'project-59', name: { en: 'Project 59', fa: 'آرامش - میرزا طاهر 4' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
{ id: '60', slug: 'project-60', name: { en: 'Project 60', fa: 'آرامش- میرزا طاهر 1' }, location: { en: 'Isfahan', fa: 'اصفهان' }, area: { en: '1000', fa: '۱۰۰۰' }, status: 'progress' },
|
|
||||||
];
|
|
||||||
@@ -54,10 +54,15 @@ export const fa = {
|
|||||||
projectNotFoundText: 'ممکن است نشانی تغییر کرده باشد. فهرست کامل پروژهها را ببینید.',
|
projectNotFoundText: 'ممکن است نشانی تغییر کرده باشد. فهرست کامل پروژهها را ببینید.',
|
||||||
backToProjects: 'بازگشت به پروژهها',
|
backToProjects: 'بازگشت به پروژهها',
|
||||||
specStatus: 'وضعیت',
|
specStatus: 'وضعیت',
|
||||||
|
specLandArea: 'مساحت عرصه (زمین)',
|
||||||
|
specPilotFloors: 'طبقات روی همکف (پیلوت)',
|
||||||
|
specUnitsResidential: 'تعداد واحد مسکونی',
|
||||||
|
specUnitsCommercial: 'تعداد واحد تجاری',
|
||||||
|
specUnitsOffice: 'تعداد واحد اداری',
|
||||||
specLocation: 'موقعیت',
|
specLocation: 'موقعیت',
|
||||||
specProjectType: 'نوع پروژه',
|
specProjectType: 'نوع پروژه',
|
||||||
specUsage: 'کاربری',
|
specUsage: 'کاربری',
|
||||||
specYear: 'سال',
|
specYear: 'سال ساخت',
|
||||||
specArea: 'زیربنا',
|
specArea: 'زیربنا',
|
||||||
specFloors: 'تعداد طبقات',
|
specFloors: 'تعداد طبقات',
|
||||||
specUnits: 'واحدها',
|
specUnits: 'واحدها',
|
||||||
@@ -170,10 +175,15 @@ export const en: Dict = {
|
|||||||
projectNotFoundText: 'The address may have changed. Browse the full list of projects.',
|
projectNotFoundText: 'The address may have changed. Browse the full list of projects.',
|
||||||
backToProjects: 'Back to projects',
|
backToProjects: 'Back to projects',
|
||||||
specStatus: 'Status',
|
specStatus: 'Status',
|
||||||
|
specLandArea: 'Land area',
|
||||||
|
specPilotFloors: 'Floors above ground',
|
||||||
|
specUnitsResidential: 'Residential units',
|
||||||
|
specUnitsCommercial: 'Commercial units',
|
||||||
|
specUnitsOffice: 'Office units',
|
||||||
specLocation: 'Location',
|
specLocation: 'Location',
|
||||||
specProjectType: 'Project type',
|
specProjectType: 'Project type',
|
||||||
specUsage: 'Land use',
|
specUsage: 'Land use',
|
||||||
specYear: 'Year',
|
specYear: 'Year built',
|
||||||
specArea: 'Built area',
|
specArea: 'Built area',
|
||||||
specFloors: 'Floors',
|
specFloors: 'Floors',
|
||||||
specUnits: 'Units',
|
specUnits: 'Units',
|
||||||
|
|||||||
@@ -54,11 +54,14 @@ export function ProjectDetail() {
|
|||||||
const facts = [
|
const facts = [
|
||||||
{ label: t('specStatus'), value: statusLabel },
|
{ label: t('specStatus'), value: statusLabel },
|
||||||
{ label: t('specYear'), value: project.year },
|
{ label: t('specYear'), value: project.year },
|
||||||
{ label: t('specFloors'), value: project.floors },
|
{ label: t('specLandArea'), value: project.land_area },
|
||||||
{ label: t('specUnits'), value: project.units },
|
|
||||||
{ label: t('specProjectType'), value: project.project_type },
|
|
||||||
{ label: t('specArea'), value: project.area },
|
{ label: t('specArea'), value: project.area },
|
||||||
{ label: t('specUsage'), value: project.usage },
|
{ label: t('specUsage'), value: project.usage },
|
||||||
|
{ label: t('specPilotFloors'), value: project.pilot_floors },
|
||||||
|
{ label: t('specFloors'), value: project.floors },
|
||||||
|
{ label: t('specUnitsResidential'), value: project.units_residential },
|
||||||
|
{ label: t('specUnitsCommercial'), value: project.units_commercial },
|
||||||
|
{ label: t('specUnitsOffice'), value: project.units_office },
|
||||||
].filter((f) => String(f.value ?? '').trim() !== '')
|
].filter((f) => String(f.value ?? '').trim() !== '')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { useLang } from '../i18n/lang';
|
|||||||
import { useFieldSaver } from '../admin/AdminContext';
|
import { useFieldSaver } from '../admin/AdminContext';
|
||||||
import { InlineEdit } from '../components/admin/InlineEdit';
|
import { InlineEdit } from '../components/admin/InlineEdit';
|
||||||
import { AddItemButton, EditableItem } from '../admin/Editable';
|
import { AddItemButton, EditableItem } from '../admin/Editable';
|
||||||
import { projectsData } from '../data/projectsData';
|
|
||||||
import { LazyProjectsMapAll } from '../map/LazyMaps';
|
import { LazyProjectsMapAll } from '../map/LazyMaps';
|
||||||
import { MAP_PROJECTS, type MapProject } from '../data/mapProjects';
|
import { MAP_PROJECTS, type MapProject } from '../data/mapProjects';
|
||||||
|
|
||||||
@@ -38,11 +37,7 @@ export function Projects() {
|
|||||||
|
|
||||||
// پروژهها از دیتابیس خوانده میشوند تا ویرایش پنل همانجا دیده شود؛
|
// پروژهها از دیتابیس خوانده میشوند تا ویرایش پنل همانجا دیده شود؛
|
||||||
// فایل استاتیک فقط وقتی دیتابیس خالی است جانشین میشود (محتوای قدیمی).
|
// فایل استاتیک فقط وقتی دیتابیس خالی است جانشین میشود (محتوای قدیمی).
|
||||||
const fromDb = dbProjects.length > 0;
|
const cardProjects = useMemo(() => dbProjects, [dbProjects]);
|
||||||
const cardProjects = useMemo(() => {
|
|
||||||
if (fromDb) return dbProjects;
|
|
||||||
return projectsData.map((p) => ({ ...p, id: Number(p.id) }));
|
|
||||||
}, [fromDb, dbProjects]);
|
|
||||||
|
|
||||||
// Filtering and Pagination State
|
// Filtering and Pagination State
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
@@ -83,11 +78,7 @@ export function Projects() {
|
|||||||
const dbMatch = dbProjects.find(
|
const dbMatch = dbProjects.find(
|
||||||
(p) => p.title === mapProject.name || p.title_en === mapProject.name,
|
(p) => p.title === mapProject.name || p.title_en === mapProject.name,
|
||||||
);
|
);
|
||||||
if (dbMatch) return `/projects/${dbMatch.slug}`;
|
return dbMatch ? `/projects/${dbMatch.slug}` : undefined;
|
||||||
const match = projectsData.find(
|
|
||||||
(p) => p.name.fa === mapProject.name || p.name.en === mapProject.name,
|
|
||||||
);
|
|
||||||
return match ? `/projects/${match.slug}` : undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -147,29 +138,22 @@ export function Projects() {
|
|||||||
{displayedProjects.map((project, index) => {
|
{displayedProjects.map((project, index) => {
|
||||||
// تصویر رکورد دیتابیس اولویت دارد؛ فقط ردیفهای بدون تصویر از
|
// تصویر رکورد دیتابیس اولویت دارد؛ فقط ردیفهای بدون تصویر از
|
||||||
// تصاویر جایگزین تکراری استفاده میکنند.
|
// تصاویر جایگزین تکراری استفاده میکنند.
|
||||||
const hasOwnImage = 'image' in project && Boolean((project as { image?: string }).image);
|
|
||||||
const imageUrl = hasOwnImage ? undefined : `${BASE_IMG_URL}${(index % 6) + 1}.png`;
|
|
||||||
const card = (
|
const card = (
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
project={project}
|
project={project}
|
||||||
imageUrl={imageUrl}
|
|
||||||
detailHref={`/projects/${project.slug}`}
|
detailHref={`/projects/${project.slug}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Reveal key={project.id} delay={0.05 * (index % itemsPerPage)} className="h-full">
|
<Reveal key={project.id} delay={0.05 * (index % itemsPerPage)} className="h-full">
|
||||||
{fromDb ? (
|
<EditableItem resource="projects" item={project} editHref={`/admin/projects/${project.id}`} className="h-full">
|
||||||
<EditableItem resource="projects" item={project} editHref={`/admin/projects/${project.id}`} className="h-full">
|
{card}
|
||||||
{card}
|
</EditableItem>
|
||||||
</EditableItem>
|
|
||||||
) : (
|
|
||||||
card
|
|
||||||
)}
|
|
||||||
</Reveal>
|
</Reveal>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{fromDb && <AddItemButton resource="projects" editHrefBase="/admin/projects" />}
|
<AddItemButton resource="projects" editHrefBase="/admin/projects" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Load More Button */}
|
{/* Load More Button */}
|
||||||
|
|||||||
Reference in New Issue
Block a user