Update homepage static-image slots and customer login links.
Align slot catalog with slider / our-experts / two-service-banner and send guests to customer portal /login. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
29ff589c5b
commit
e7e5381b80
@@ -3,11 +3,11 @@ Wire this page to clinicsamen.com, static-image slots.
|
||||
Read http://meshkee.com/docs/website (static-images). Env is already set.
|
||||
|
||||
Fetch slots, match by key:
|
||||
- slider > duplicatable
|
||||
- 4 people image > 4 slot
|
||||
- our-services-icon > 4 slot
|
||||
- two-banner-bg > 2 slot
|
||||
- slider > duplicatable
|
||||
- our-experts > duplicatable
|
||||
- two-service-banner > 2 slot
|
||||
|
||||
check the original UI, use name fa, name en and subtex according to it
|
||||
|
||||
Use slot.images (all of them if kind=list, first if kind=single).
|
||||
url → <img src>. linkUrl → wrap in <a>. Empty or fail → keep current placeholder.
|
||||
@@ -15,4 +15,4 @@ Use slot.aspectRatio from the API. Do not invent upload APIs.
|
||||
|
||||
If image size or aspect ratio has changed during development, please update it for statics image reader. Add this as rule
|
||||
|
||||
update context md for better use in other Ai and systems - update it on every prompt (If required)
|
||||
update context md for better use in other Ai and systems - update it on every prompt (If required)
|
||||
|
||||
+16
-9
@@ -59,12 +59,13 @@ Helpers: `src/lib/meshkee.ts` → `meshkeeGet`, `tenantPath`, `getTenant`, `getB
|
||||
- **Note:** Tenant currently has no published workshops in API; homepage/list fall back to static samples in `src/data/site.ts`.
|
||||
|
||||
### Auth / customer portal
|
||||
- Login icon → `https://customer.clinicsamen.com` (`customerPortalUrl` in `src/lib/config.ts`)
|
||||
- Session: `src/lib/session.tsx` + shared cookies (`src/lib/shared-auth-cookie.ts`)
|
||||
- Login / user icon → `https://customer.{domain}/login` (`customerPortalUrl` in `src/lib/config.ts` → `customer.clinicsamen.com`)
|
||||
- Session: `src/lib/session.tsx` + shared cookies (`src/lib/shared-auth-cookie.ts`) — reads `meshkee_customer_access_token` from parent domain
|
||||
- Profile API proxy: `GET /api/auth/me` → Meshkee `/auth/me`
|
||||
- Admin handoff: `POST /api/auth/handoff` → Meshkee `/auth/handoff` → `https://business.clinicsamen.com`
|
||||
- Logged-in header: user name + «عزیز»; dropdown: پروفایل من، خروج، مدیریت وبسایت (admins only)
|
||||
- Component: `src/components/AccountMenu.tsx`
|
||||
- Logged-in header: `{firstName lastName} عزیز` via `userDisplayName`
|
||||
- Dropdown (`AccountMenu`): پروفایل من → `/profile`; مدیریت وبسایت (admins/owners/team only, handoff ticket); خروج (clears shared cookies)
|
||||
- Component: `src/components/AccountMenu.tsx` (wired in `Header` topbar)
|
||||
|
||||
## Static image slots
|
||||
API: `GET /tenants/{domain}/website/static-images?pageKey=home`
|
||||
@@ -72,17 +73,23 @@ Catalog for dashboard Refresh: `GET /meshkee/static-image-slots` → `STATIC_IMA
|
||||
|
||||
| key | kind | itemCount | aspectRatio | recommendedWidth | homepage section |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slider` | list | null | `1920:740` | 1180 | Hero slider |
|
||||
| `4-people-image` | list | 4 | `325:356` | 280 | Home therapists row |
|
||||
| `our-services-icon` | list | 4 | `1:1` | 110 | Services icons |
|
||||
| `two-banner-bg` | list | 2 | `540:312` | 560 | Dual promo banners |
|
||||
| `slider` | list (duplicatable) | null | `1920:740` | 1180 | Hero slider |
|
||||
| `our-experts` | list (duplicatable) | null | `325:356` | 280 | Home therapists / experts row |
|
||||
| `two-service-banner` | list | 2 | `540:312` | 560 | Dual promo banners under services |
|
||||
|
||||
Field → UI mapping (match original homepage; empty API → local placeholders):
|
||||
- `slider`: `url` → slide image; `linkUrl` → wrap slide. `titleFa` / `titleEn` / `subtext` not rendered in hero (image-only).
|
||||
- `our-experts`: `url` → photo; `linkUrl` → card link (fallback `/ourdr`); `titleFa` → name (`h3`); `subtext` → role (`p`). `titleEn` not shown (original therapist cards have no English line).
|
||||
- `two-service-banner`: `url` → banner background; `linkUrl` → CTA href; `titleFa` → banner title (`h3`). `titleEn` / `subtext` not shown on banners.
|
||||
|
||||
Service icons on the homepage stay local (`serviceCards` in `src/data/site.ts`) — not a Meshkee static-image slot.
|
||||
|
||||
Rules:
|
||||
- Use `slot.images` (all if `kind=list`, first if `kind=single`)
|
||||
- `url` → `<img src>`; `linkUrl` → wrap in link
|
||||
- Empty / fail → keep local placeholders from `src/data/site.ts` / `public/images/`
|
||||
- Use `slot.aspectRatio` (via `parseAspectRatio`)
|
||||
- **If a slot’s on-page size or aspect ratio changes in CSS, update `STATIC_IMAGE_SLOTS` in the same change**
|
||||
- **If a slot’s on-page size or aspect ratio changes in CSS, update `STATIC_IMAGE_SLOTS` in the same change** (Meshkee reads the catalog as the static-image source of truth)
|
||||
|
||||
Helpers: `src/lib/static-images.ts`, `src/components/SlotImage.tsx`, `src/components/SlotLink.tsx`
|
||||
Home wiring: `src/app/page.tsx`
|
||||
|
||||
+16
-17
@@ -27,6 +27,7 @@ export default async function HomePage() {
|
||||
: getLocalBlogPosts();
|
||||
const workshops = workshopResult.items;
|
||||
|
||||
// slider: titleFa / titleEn / subtext unused in hero UI (image + optional linkUrl only)
|
||||
const slider = overlaySlotImages(
|
||||
pickSlot(slots, "slider"),
|
||||
slides.map((slide, index) => {
|
||||
@@ -41,8 +42,9 @@ export default async function HomePage() {
|
||||
"slider",
|
||||
);
|
||||
|
||||
// our-experts: titleFa → name, subtext → role (titleEn not shown in original therapist cards)
|
||||
const people = overlaySlotImages(
|
||||
pickSlot(slots, "4-people-image"),
|
||||
pickSlot(slots, "our-experts"),
|
||||
homeTherapists.map((person, index) => ({
|
||||
id: `person-${index}`,
|
||||
image: person.image,
|
||||
@@ -50,23 +52,21 @@ export default async function HomePage() {
|
||||
title: person.name,
|
||||
text: person.role,
|
||||
})),
|
||||
"4-people-image",
|
||||
"our-experts",
|
||||
);
|
||||
|
||||
const serviceIcons = overlaySlotImages(
|
||||
pickSlot(slots, "our-services-icon"),
|
||||
serviceCards.map((service, index) => ({
|
||||
id: `service-${index}`,
|
||||
image: service.image,
|
||||
href: service.href,
|
||||
title: service.title,
|
||||
kicker: service.english,
|
||||
})),
|
||||
"our-services-icon",
|
||||
);
|
||||
// Local service icons (not a Meshkee static-image slot)
|
||||
const serviceIcons = serviceCards.map((service, index) => ({
|
||||
id: `service-${index}`,
|
||||
image: service.image,
|
||||
href: service.href,
|
||||
title: service.title,
|
||||
kicker: service.english,
|
||||
}));
|
||||
|
||||
// two-service-banner: titleFa → banner title (titleEn / subtext not shown in original banner UI)
|
||||
const banners = overlaySlotImages(
|
||||
pickSlot(slots, "two-banner-bg"),
|
||||
pickSlot(slots, "two-service-banner"),
|
||||
[
|
||||
{
|
||||
id: "banner-workshops",
|
||||
@@ -81,7 +81,7 @@ export default async function HomePage() {
|
||||
title: "مشاوره فردی",
|
||||
},
|
||||
],
|
||||
"two-banner-bg",
|
||||
"two-service-banner",
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -90,8 +90,7 @@ export default async function HomePage() {
|
||||
<HomeSections
|
||||
people={people.items}
|
||||
peopleAspectRatio={people.aspectRatio}
|
||||
serviceIcons={serviceIcons.items}
|
||||
serviceIconsAspectRatio={serviceIcons.aspectRatio}
|
||||
serviceIcons={serviceIcons}
|
||||
banners={banners.items}
|
||||
bannersAspectRatio={banners.aspectRatio}
|
||||
workshops={workshops}
|
||||
|
||||
@@ -106,7 +106,11 @@ export default function AccountMenu() {
|
||||
|
||||
if (!isAuthenticated || !user) {
|
||||
return (
|
||||
<a href={customerPortalUrl} className="account-menu account-menu--login" aria-label="ورود / ثبتنام">
|
||||
<a
|
||||
href={`${customerPortalUrl}/login`}
|
||||
className="account-menu account-menu--login"
|
||||
aria-label="ورود / ثبتنام"
|
||||
>
|
||||
<UserIcon />
|
||||
<span>ورود / ثبتنام</span>
|
||||
</a>
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function EntityTabs({
|
||||
<div className="login-prompt">
|
||||
<p className="login-prompt__title">برای ثبت نظر وارد شوید</p>
|
||||
<p className="login-prompt__text">نظرات فقط برای کاربران واردشده فعال است.</p>
|
||||
<a href={customerPortalUrl} className="btn btn-primary">
|
||||
<a href={`${customerPortalUrl}/login`} className="btn btn-primary">
|
||||
ورود / ثبتنام
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,6 @@ type Props = {
|
||||
people: SlotMediaItem[];
|
||||
peopleAspectRatio?: string;
|
||||
serviceIcons: SlotMediaItem[];
|
||||
serviceIconsAspectRatio?: string;
|
||||
banners: SlotMediaItem[];
|
||||
bannersAspectRatio?: string;
|
||||
workshops: Workshop[];
|
||||
@@ -25,14 +24,12 @@ export default function HomeSections({
|
||||
people,
|
||||
peopleAspectRatio,
|
||||
serviceIcons,
|
||||
serviceIconsAspectRatio,
|
||||
banners,
|
||||
bannersAspectRatio,
|
||||
workshops,
|
||||
articles,
|
||||
}: Props) {
|
||||
const peopleRatio = parseAspectRatio(peopleAspectRatio) ?? "325 / 356";
|
||||
const iconRatio = parseAspectRatio(serviceIconsAspectRatio) ?? "1 / 1";
|
||||
const bannerRatio = parseAspectRatio(bannersAspectRatio) ?? "540 / 312";
|
||||
|
||||
return (
|
||||
@@ -129,7 +126,7 @@ export default function HomeSections({
|
||||
<div className="service-grid">
|
||||
{serviceIcons.map((item) => (
|
||||
<SlotLink key={item.id} href={item.href || "/#services"} className="service-card">
|
||||
<div className="service-icon" style={{ aspectRatio: iconRatio }}>
|
||||
<div className="service-icon" style={{ aspectRatio: "1 / 1" }}>
|
||||
<SlotImage
|
||||
src={item.image}
|
||||
fallbackSrc={item.fallbackSrc}
|
||||
|
||||
@@ -92,7 +92,7 @@ export default function WorkshopRegistration({
|
||||
) : (
|
||||
<div className="login-prompt login-prompt--inline">
|
||||
<p className="login-prompt__title">برای ثبتنام در کارگاه وارد شوید</p>
|
||||
<a href={customerPortalUrl} className="btn btn-primary">
|
||||
<a href={`${customerPortalUrl}/login`} className="btn btn-primary">
|
||||
ورود / ثبتنام
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -55,26 +55,17 @@ export const STATIC_IMAGE_SLOTS: StaticImageSlotCatalogItem[] = [
|
||||
recommendedWidth: 1180,
|
||||
},
|
||||
{
|
||||
key: "4-people-image",
|
||||
label: "Four people images",
|
||||
key: "our-experts",
|
||||
label: "Our experts",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "325:356",
|
||||
itemCount: 4,
|
||||
itemCount: null,
|
||||
recommendedWidth: 280,
|
||||
},
|
||||
{
|
||||
key: "our-services-icon",
|
||||
label: "Our services icons",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "1:1",
|
||||
itemCount: 4,
|
||||
recommendedWidth: 110,
|
||||
},
|
||||
{
|
||||
key: "two-banner-bg",
|
||||
label: "Two banner backgrounds",
|
||||
key: "two-service-banner",
|
||||
label: "Two service banners",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "540:312",
|
||||
|
||||
Reference in New Issue
Block a user