Skip to content

Commit ffefcdf

Browse files
Add Mom & Baby vertical features
Implemented full Mom & Baby section with lifecycle navigation, concern filters, and beauty advisor booking. Added /mom-baby route, wired header navigation, and integrated multilingual support. Created components: MomBaby, MomBabyHero, LifecycleNav, LifecycleSection, ConcernFilters, BeautyAdvisors, MomBabyBrands. Wired routing, updated header, and added necessary UI placeholders and translations. X-Lovable-Edit-ID: edt-c0835002-e7fa-41c6-81ce-00de9923d35c
2 parents 64e61d9 + 7e00174 commit ffefcdf

9 files changed

Lines changed: 611 additions & 0 deletions

File tree

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const Profile = lazy(() => import("./pages/Profile"));
2525
const Contact = lazy(() => import("./pages/Contact"));
2626
const Shop = lazy(() => import("./pages/Shop"));
2727
const Health = lazy(() => import("./pages/Health"));
28+
const MomBaby = lazy(() => import("./pages/MomBaby"));
2829

2930
const queryClient = new QueryClient();
3031

@@ -73,6 +74,7 @@ function AppContent() {
7374
<Route path="/contact" element={<Contact />} />
7475
<Route path="/admin/enrichment" element={<AdminEnrichment />} />
7576
<Route path="/health" element={<Health />} />
77+
<Route path="/mom-baby" element={<MomBaby />} />
7678
<Route path="*" element={<NotFound />} />
7779
</Routes>
7880
</Suspense>

src/components/Header.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ export const Header = () => {
4949
<Link to="/shop" className="text-sm font-medium text-foreground/80 hover:text-primary transition-colors font-body">
5050
{t("nav.shop")}
5151
</Link>
52+
<Link to="/mom-baby" className="text-sm font-medium text-foreground/80 hover:text-primary transition-colors font-body">
53+
{locale === "ar" ? "الأم والطفل" : "Mom & Baby"}
54+
</Link>
5255
<Link to="/products" className="text-sm font-medium text-foreground/80 hover:text-primary transition-colors font-body">
5356
Products
5457
</Link>
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { useLanguage } from "@/contexts/LanguageContext";
2+
import { Button } from "@/components/ui/button";
3+
import { Calendar, BadgePercent, Star } from "lucide-react";
4+
import { motion } from "framer-motion";
5+
6+
const advisors = [
7+
{
8+
name: "Dr. Lina",
9+
nameAr: "د. لينا",
10+
specialty: { en: "Dermocosmetics", ar: "مستحضرات التجميل الطبية" },
11+
discount: 25,
12+
experience: "8+ yrs",
13+
availability: { en: "Thursday", ar: "الخميس" },
14+
},
15+
{
16+
name: "Rawan",
17+
nameAr: "روان",
18+
specialty: { en: "Clinical Supplementation", ar: "المكملات السريرية" },
19+
discount: 20,
20+
experience: "5+ yrs",
21+
availability: { en: "Tuesday", ar: "الثلاثاء" },
22+
},
23+
{
24+
name: "Sarah",
25+
nameAr: "سارة",
26+
specialty: { en: "Maternal Wellness", ar: "صحة الأم" },
27+
discount: 15,
28+
experience: "6+ yrs",
29+
availability: { en: "Friday", ar: "الجمعة" },
30+
},
31+
{
32+
name: "Nour",
33+
nameAr: "نور",
34+
specialty: { en: "Pediatric Skincare", ar: "عناية بشرة الأطفال" },
35+
discount: 20,
36+
experience: "10+ yrs",
37+
availability: { en: "On Demand", ar: "عند الطلب" },
38+
},
39+
];
40+
41+
export default function BeautyAdvisors() {
42+
const { locale } = useLanguage();
43+
const isAr = locale === "ar";
44+
45+
return (
46+
<section className="py-16 bg-primary/[0.02]">
47+
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
48+
<div className="text-center mb-10">
49+
<span className="inline-flex items-center gap-2 rounded-full border border-accent/30 bg-accent/5 px-4 py-1.5 text-xs font-body uppercase tracking-widest text-accent mb-4">
50+
<Star className="w-3.5 h-3.5" />
51+
{isAr ? "استشارة شخصية" : "Personal Consultation"}
52+
</span>
53+
<h2 className="font-heading text-3xl md:text-4xl text-foreground mb-3">
54+
{isAr ? "مستشاراتنا المتخصصات" : "Our Expert Advisors"}
55+
</h2>
56+
<p className="font-body text-muted-foreground max-w-xl mx-auto">
57+
{isAr
58+
? "احجزي موعداً مجانياً مع مستشارتنا المتخصصة واحصلي على خصم حصري على مشترياتك."
59+
: "Book a free session with our specialist and receive an exclusive discount on your purchases."}
60+
</p>
61+
</div>
62+
63+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5">
64+
{advisors.map((advisor, i) => (
65+
<motion.div
66+
key={advisor.name}
67+
initial={{ opacity: 0, y: 20 }}
68+
whileInView={{ opacity: 1, y: 0 }}
69+
viewport={{ once: true }}
70+
transition={{ delay: i * 0.1, duration: 0.4 }}
71+
className="product-card-hover group rounded-xl border border-border bg-card p-6 text-center"
72+
>
73+
{/* Avatar placeholder */}
74+
<div className="w-16 h-16 rounded-full bg-primary/10 mx-auto mb-4 flex items-center justify-center">
75+
<span className="text-xl font-heading font-bold text-primary">
76+
{advisor.name.charAt(0)}
77+
</span>
78+
</div>
79+
80+
<h3 className="font-heading text-lg text-foreground mb-1">
81+
{isAr ? advisor.nameAr : advisor.name}
82+
</h3>
83+
<p className="text-xs font-body text-accent uppercase tracking-wider mb-2">
84+
{isAr ? advisor.specialty.ar : advisor.specialty.en}
85+
</p>
86+
<p className="text-[10px] font-body text-muted-foreground mb-4">
87+
{advisor.experience}
88+
</p>
89+
90+
{/* Discount badge */}
91+
<div className="inline-flex items-center gap-1.5 rounded-full bg-accent/10 text-accent px-3 py-1 text-xs font-body font-medium mb-4">
92+
<BadgePercent className="w-3.5 h-3.5" />
93+
-{advisor.discount}% {isAr ? "خصم" : "off"}
94+
</div>
95+
96+
{/* Availability */}
97+
<div className="flex items-center justify-center gap-1.5 text-xs text-muted-foreground mb-4">
98+
<Calendar className="w-3 h-3" />
99+
{isAr ? advisor.availability.ar : advisor.availability.en}
100+
</div>
101+
102+
<Button
103+
size="sm"
104+
className="w-full btn-ripple"
105+
>
106+
{isAr ? "احجزي الآن" : "Book Now"}
107+
</Button>
108+
</motion.div>
109+
))}
110+
</div>
111+
</div>
112+
</section>
113+
);
114+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { useLanguage } from "@/contexts/LanguageContext";
2+
import { cn } from "@/lib/utils";
3+
import { X } from "lucide-react";
4+
5+
const concerns = [
6+
{ id: "hygiene", en: "Personal Hygiene", ar: "النظافة الشخصية", count: 230 },
7+
{ id: "atopic", en: "Atopic Dermatitis", ar: "التهاب الجلد التأتبي", count: 85 },
8+
{ id: "first-teeth", en: "First Teeth", ar: "الأسنان الأولى", count: 34 },
9+
{ id: "special-care", en: "Special Care", ar: "العناية الخاصة", count: 33 },
10+
{ id: "nasal", en: "Nasal Congestion", ar: "احتقان الأنف", count: 26 },
11+
{ id: "dehydration", en: "Dehydration", ar: "الجفاف", count: 19 },
12+
{ id: "cradle-cap", en: "Cradle Cap", ar: "قبعة المهد", count: 13 },
13+
{ id: "colic", en: "Cramps & Colic", ar: "التشنجات والمغص", count: 12 },
14+
{ id: "lice", en: "Lice", ar: "القمل", count: 11 },
15+
{ id: "seborrheic", en: "Seborrheic Dermatitis", ar: "التهاب الجلد المثّي", count: 8 },
16+
{ id: "sensitive", en: "Sensitive Skin", ar: "البشرة الحساسة", count: 6 },
17+
{ id: "stretch-marks", en: "Stretch Marks", ar: "علامات التمدد", count: 5 },
18+
{ id: "sun-protection", en: "Sun Protection", ar: "الحماية من الشمس", count: 4 },
19+
];
20+
21+
interface Props {
22+
activeConcern: string | null;
23+
onConcernChange: (concern: string | null) => void;
24+
}
25+
26+
export default function ConcernFilters({ activeConcern, onConcernChange }: Props) {
27+
const { locale } = useLanguage();
28+
const isAr = locale === "ar";
29+
30+
return (
31+
<section className="py-6 bg-muted/30">
32+
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
33+
<div className="flex items-center justify-between mb-3">
34+
<h3 className="font-heading text-base text-foreground">
35+
{isAr ? "تصفية حسب القلق" : "Filter by Concern"}
36+
</h3>
37+
{activeConcern && (
38+
<button
39+
onClick={() => onConcernChange(null)}
40+
className="inline-flex items-center gap-1 text-xs font-body text-muted-foreground hover:text-primary transition-colors"
41+
>
42+
<X className="w-3 h-3" />
43+
{isAr ? "مسح" : "Clear"}
44+
</button>
45+
)}
46+
</div>
47+
<div className="flex gap-2 overflow-x-auto pb-2 scrollbar-hide">
48+
{concerns.map((concern) => {
49+
const active = activeConcern === concern.id;
50+
return (
51+
<button
52+
key={concern.id}
53+
onClick={() => onConcernChange(active ? null : concern.id)}
54+
className={cn(
55+
"inline-flex items-center gap-1.5 whitespace-nowrap rounded-full px-3.5 py-1.5 text-xs font-body transition-all duration-200 border shrink-0",
56+
active
57+
? "border-primary bg-primary text-primary-foreground"
58+
: "border-border bg-card text-foreground hover:border-accent/50"
59+
)}
60+
>
61+
{isAr ? concern.ar : concern.en}
62+
<span
63+
className={cn(
64+
"text-[10px] rounded-full px-1.5 py-0.5",
65+
active
66+
? "bg-primary-foreground/20 text-primary-foreground"
67+
: "bg-muted text-muted-foreground"
68+
)}
69+
>
70+
{concern.count}
71+
</span>
72+
</button>
73+
);
74+
})}
75+
</div>
76+
</div>
77+
</section>
78+
);
79+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { useLanguage } from "@/contexts/LanguageContext";
2+
import type { LifecyclePhase } from "@/pages/MomBaby";
3+
import { cn } from "@/lib/utils";
4+
import { Heart, Baby, Sparkles, ShoppingBag, LayoutGrid } from "lucide-react";
5+
6+
const phases: {
7+
id: LifecyclePhase;
8+
en: string;
9+
ar: string;
10+
icon: typeof Heart;
11+
description: { en: string; ar: string };
12+
}[] = [
13+
{
14+
id: "all",
15+
en: "All",
16+
ar: "الكل",
17+
icon: LayoutGrid,
18+
description: { en: "Browse everything", ar: "تصفح الكل" },
19+
},
20+
{
21+
id: "before-birth",
22+
en: "Before Birth",
23+
ar: "قبل الولادة",
24+
icon: Heart,
25+
description: { en: "Prenatal care & supplements", ar: "رعاية ما قبل الولادة والمكملات" },
26+
},
27+
{
28+
id: "after-birth",
29+
en: "After Birth",
30+
ar: "بعد الولادة",
31+
icon: Sparkles,
32+
description: { en: "Recovery & lactation", ar: "التعافي والرضاعة" },
33+
},
34+
{
35+
id: "first-years",
36+
en: "First Years",
37+
ar: "السنوات الأولى",
38+
icon: Baby,
39+
description: { en: "Pediatric skincare & feeding", ar: "العناية بالبشرة والتغذية" },
40+
},
41+
{
42+
id: "essentials",
43+
en: "Essentials",
44+
ar: "أساسيات الأمومة",
45+
icon: ShoppingBag,
46+
description: { en: "Hospital bags & hardware", ar: "حقيبة المستشفى والمستلزمات" },
47+
},
48+
];
49+
50+
interface Props {
51+
activePhase: LifecyclePhase;
52+
onPhaseChange: (phase: LifecyclePhase) => void;
53+
}
54+
55+
export default function LifecycleNav({ activePhase, onPhaseChange }: Props) {
56+
const { locale } = useLanguage();
57+
const isAr = locale === "ar";
58+
59+
return (
60+
<section className="py-8 border-b border-border">
61+
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
62+
<h2 className="font-heading text-lg text-foreground mb-4 text-center">
63+
{isAr ? "اختاري مرحلتك" : "Choose Your Stage"}
64+
</h2>
65+
<div className="flex gap-3 overflow-x-auto pb-2 scrollbar-hide justify-center flex-wrap">
66+
{phases.map((phase) => {
67+
const active = activePhase === phase.id;
68+
return (
69+
<button
70+
key={phase.id}
71+
onClick={() => onPhaseChange(phase.id)}
72+
className={cn(
73+
"group flex flex-col items-center gap-1.5 rounded-xl px-5 py-3 text-center transition-all duration-300 border min-w-[120px]",
74+
active
75+
? "border-primary bg-primary/5 shadow-warm"
76+
: "border-border bg-card hover:border-accent/50 hover:shadow-warm"
77+
)}
78+
>
79+
<phase.icon
80+
className={cn(
81+
"w-5 h-5 transition-colors",
82+
active ? "text-primary" : "text-muted-foreground group-hover:text-accent"
83+
)}
84+
/>
85+
<span
86+
className={cn(
87+
"text-sm font-body font-medium",
88+
active ? "text-primary" : "text-foreground"
89+
)}
90+
>
91+
{isAr ? phase.ar : phase.en}
92+
</span>
93+
<span className="text-[10px] text-muted-foreground font-body leading-tight">
94+
{isAr ? phase.description.ar : phase.description.en}
95+
</span>
96+
</button>
97+
);
98+
})}
99+
</div>
100+
</div>
101+
</section>
102+
);
103+
}

0 commit comments

Comments
 (0)