@jhits/plugin-website 0.0.12 β†’ 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/api/handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;GAEG;AACH,wBAAsB,YAAY,CAC9B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC,CA6CvB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAC/B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC,CAmFvB"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/api/handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;GAEG;AACH,wBAAsB,YAAY,CAC9B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC,CAuDvB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAC/B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC,CAmFvB"}
@@ -28,6 +28,16 @@ export async function GET_SETTINGS(req, config) {
28
28
  maintenanceMode: false,
29
29
  launch_date: '',
30
30
  socials: [],
31
+ localizedContactInfo: {
32
+ en: { physicalAddress: '', phoneNumber: '' },
33
+ sv: { physicalAddress: '', phoneNumber: '' },
34
+ nl: { physicalAddress: '', phoneNumber: '' },
35
+ },
36
+ localizedSocials: {
37
+ en: [],
38
+ sv: [],
39
+ nl: [],
40
+ },
31
41
  });
32
42
  }
33
43
  // Convert launch_date from Date to ISO string if it exists
@@ -1,6 +1,16 @@
1
1
  /**
2
2
  * Website Settings Types
3
3
  */
4
+ export type SupportedLocale = 'en' | 'sv' | 'nl';
5
+ export interface LocalizedContactInfo {
6
+ physicalAddress?: string;
7
+ phoneNumber?: string;
8
+ }
9
+ export interface LocalizedSocialLink {
10
+ id: number;
11
+ platform: string;
12
+ url: string;
13
+ }
4
14
  export interface WebsiteSettings {
5
15
  identifier: string;
6
16
  siteName?: string;
@@ -14,6 +24,8 @@ export interface WebsiteSettings {
14
24
  maintenanceMode?: boolean;
15
25
  launch_date?: string;
16
26
  socials?: SocialLink[];
27
+ localizedContactInfo?: Partial<Record<SupportedLocale, LocalizedContactInfo>>;
28
+ localizedSocials?: Partial<Record<SupportedLocale, LocalizedSocialLink[]>>;
17
29
  updatedAt?: Date;
18
30
  createdAt?: Date;
19
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/types/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,GAAG,CAAA;KAAE,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/types/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;IAC3E,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,GAAG,CAAA;KAAE,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsView.d.ts","sourceRoot":"","sources":["../../src/views/SettingsView.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,iBAAiB,2CA2ejE"}
1
+ {"version":3,"file":"SettingsView.d.ts","sourceRoot":"","sources":["../../src/views/SettingsView.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAyBH,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,iBAAiB,2CA2kBjE"}
@@ -8,6 +8,11 @@ import { useState, useEffect, useRef } from 'react';
8
8
  import { Save, RefreshCw, Globe, Mail, Search, Settings2, Calendar } from 'lucide-react';
9
9
  import { FaFacebook, FaInstagram, FaLinkedin, FaPinterest, FaTiktok } from 'react-icons/fa';
10
10
  import { FaXTwitter } from 'react-icons/fa6';
11
+ const AVAILABLE_LOCALES = [
12
+ { code: 'en', name: 'English', flag: 'πŸ‡¬πŸ‡§' },
13
+ { code: 'sv', name: 'Swedish', flag: 'πŸ‡ΈπŸ‡ͺ' },
14
+ { code: 'nl', name: 'Dutch', flag: 'πŸ‡³πŸ‡±' },
15
+ ];
11
16
  const AVAILABLE_PLATFORMS = [
12
17
  { name: 'Instagram', icon: _jsx(FaInstagram, { size: 18 }) },
13
18
  { name: 'Facebook', icon: _jsx(FaFacebook, { size: 18 }) },
@@ -20,6 +25,7 @@ export function SettingsView({ siteId, locale }) {
20
25
  const [isLoading, setIsLoading] = useState(true);
21
26
  const [isSaving, setIsSaving] = useState(false);
22
27
  const [showSuccess, setShowSuccess] = useState(false);
28
+ const [activeTab, setActiveTab] = useState('en');
23
29
  const [settings, setSettings] = useState({
24
30
  identifier: 'site_config',
25
31
  siteName: '',
@@ -33,6 +39,16 @@ export function SettingsView({ siteId, locale }) {
33
39
  maintenanceMode: false,
34
40
  launch_date: '',
35
41
  socials: [],
42
+ localizedContactInfo: {
43
+ en: { physicalAddress: '', phoneNumber: '' },
44
+ sv: { physicalAddress: '', phoneNumber: '' },
45
+ nl: { physicalAddress: '', phoneNumber: '' },
46
+ },
47
+ localizedSocials: {
48
+ en: [],
49
+ sv: [],
50
+ nl: [],
51
+ },
36
52
  });
37
53
  // Fetch settings on load
38
54
  useEffect(() => {
@@ -88,6 +104,16 @@ export function SettingsView({ siteId, locale }) {
88
104
  maintenanceMode: data.maintenanceMode ?? false,
89
105
  launch_date: launchDate,
90
106
  socials: data.socials || [],
107
+ localizedContactInfo: data.localizedContactInfo || {
108
+ en: { physicalAddress: '', phoneNumber: '' },
109
+ sv: { physicalAddress: '', phoneNumber: '' },
110
+ nl: { physicalAddress: '', phoneNumber: '' },
111
+ },
112
+ localizedSocials: data.localizedSocials || {
113
+ en: [],
114
+ sv: [],
115
+ nl: [],
116
+ },
91
117
  });
92
118
  }
93
119
  }
@@ -151,26 +177,58 @@ export function SettingsView({ siteId, locale }) {
151
177
  setIsSaving(false);
152
178
  }
153
179
  };
154
- // Add social link
155
- const handleAddSocial = () => {
156
- const newId = settings.socials?.length ? Math.max(...settings.socials.map(s => s.id)) + 1 : 1;
180
+ // Remove social link
181
+ const handleRemoveSocial = (id) => {
157
182
  setSettings({
158
183
  ...settings,
159
- socials: [...(settings.socials || []), { id: newId, platform: '', url: '' }],
184
+ socials: settings.socials?.filter(social => social.id !== id) || [],
160
185
  });
161
186
  };
162
- // Update social link
163
- const handleUpdateSocial = (id, field, value) => {
187
+ // Update localized contact info
188
+ const handleUpdateLocalizedContact = (field, value) => {
164
189
  setSettings({
165
190
  ...settings,
166
- socials: settings.socials?.map(social => social.id === id ? { ...social, [field]: value } : social) || [],
191
+ localizedContactInfo: {
192
+ ...settings.localizedContactInfo,
193
+ [activeTab]: {
194
+ ...settings.localizedContactInfo?.[activeTab],
195
+ [field]: value,
196
+ },
197
+ },
167
198
  });
168
199
  };
169
- // Remove social link
170
- const handleRemoveSocial = (id) => {
200
+ // Add localized social link
201
+ const handleAddLocalizedSocial = () => {
202
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
203
+ const newId = currentSocials.length ? Math.max(...currentSocials.map(s => s.id)) + 1 : 1;
171
204
  setSettings({
172
205
  ...settings,
173
- socials: settings.socials?.filter(social => social.id !== id) || [],
206
+ localizedSocials: {
207
+ ...settings.localizedSocials,
208
+ [activeTab]: [...currentSocials, { id: newId, platform: '', url: '' }],
209
+ },
210
+ });
211
+ };
212
+ // Update localized social link
213
+ const handleUpdateLocalizedSocial = (id, field, value) => {
214
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
215
+ setSettings({
216
+ ...settings,
217
+ localizedSocials: {
218
+ ...settings.localizedSocials,
219
+ [activeTab]: currentSocials.map(social => social.id === id ? { ...social, [field]: value } : social),
220
+ },
221
+ });
222
+ };
223
+ // Remove localized social link
224
+ const handleRemoveLocalizedSocial = (id) => {
225
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
226
+ setSettings({
227
+ ...settings,
228
+ localizedSocials: {
229
+ ...settings.localizedSocials,
230
+ [activeTab]: currentSocials.filter(social => social.id !== id),
231
+ },
174
232
  });
175
233
  };
176
234
  if (isLoading) {
@@ -180,10 +238,17 @@ export function SettingsView({ siteId, locale }) {
180
238
  ? 'bg-neutral-400 text-white cursor-not-allowed'
181
239
  : showSuccess
182
240
  ? 'bg-green-600 text-white'
183
- : 'bg-primary text-white hover:bg-primary/90'}`, children: isSaving ? (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "w-4 h-4 animate-spin" }), "Saving..."] })) : showSuccess ? (_jsxs(_Fragment, { children: [_jsx(Settings2, { className: "w-4 h-4" }), "Saved!"] })) : (_jsxs(_Fragment, { children: [_jsx(Save, { className: "w-4 h-4" }), "Save Settings"] })) })] }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-8", children: [_jsxs("div", { className: "lg:col-span-2 space-y-8", children: [_jsxs("section", { className: "bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Search, { size: 20, className: "text-primary" }), "Website Identity & SEO"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Website Name" }), _jsx("input", { type: "text", value: settings.siteName || '', onChange: (e) => setSettings({ ...settings, siteName: e.target.value }), placeholder: "e.g., Botanics & You", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Website Tagline" }), _jsx("input", { type: "text", value: settings.siteTagline || '', onChange: (e) => setSettings({ ...settings, siteTagline: e.target.value }), placeholder: "e.g., Sharing my knowledge with you", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] })] }), _jsxs("div", { className: "mt-6 space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Website Description" }), _jsx("textarea", { value: settings.siteDescription || '', onChange: (e) => setSettings({ ...settings, siteDescription: e.target.value }), placeholder: "A brief description of your website", rows: 3, className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text resize-none" })] }), _jsxs("div", { className: "mt-6 space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Keywords (comma-separated)" }), _jsx("input", { type: "text", value: settings.keywords || '', onChange: (e) => setSettings({ ...settings, keywords: e.target.value }), placeholder: "keyword1, keyword2, keyword3", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] })] }), _jsxs("section", { className: "bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Mail, { size: 20, className: "text-primary" }), "Contact Information"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Contact Email" }), _jsx("input", { type: "email", value: settings.contactEmail || '', onChange: (e) => setSettings({ ...settings, contactEmail: e.target.value }), placeholder: "contact@example.com", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Phone Number" }), _jsx("input", { type: "tel", value: settings.phoneNumber || '', onChange: (e) => setSettings({ ...settings, phoneNumber: e.target.value }), placeholder: "+31 6 12345678", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] })] }), _jsxs("div", { className: "mt-6 space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Physical Address" }), _jsx("textarea", { value: settings.physicalAddress || '', onChange: (e) => setSettings({ ...settings, physicalAddress: e.target.value }), placeholder: "Street address, City, Country", rows: 2, className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text resize-none" })] })] }), _jsxs("section", { className: "bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-dashboard-border pb-4 mb-6", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text", children: [_jsx(Globe, { size: 20, className: "text-primary" }), "Social Links"] }), _jsx("button", { onClick: handleAddSocial, className: "px-4 py-2 text-xs font-bold uppercase tracking-widest bg-primary text-white rounded-full hover:bg-primary/90 transition-all", children: "Add Social" })] }), _jsx("div", { className: "space-y-4", children: settings.socials && settings.socials.length > 0 ? (settings.socials.map((social) => {
184
- const platform = AVAILABLE_PLATFORMS.find(p => p.name === social.platform);
185
- return (_jsxs("div", { className: "flex items-center gap-4 p-4 bg-dashboard-card rounded-2xl border border-dashboard-border", children: [_jsx("div", { className: "flex-shrink-0 text-dashboard-text-secondary", children: platform?.icon || _jsx(Globe, { size: 18 }) }), _jsxs("select", { value: social.platform, onChange: (e) => handleUpdateSocial(social.id, 'platform', e.target.value), className: "flex-1 px-4 py-2 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text", children: [_jsx("option", { value: "", children: "Select Platform" }), AVAILABLE_PLATFORMS.map(p => (_jsx("option", { value: p.name, children: p.name }, p.name)))] }), _jsx("input", { type: "url", value: social.url, onChange: (e) => handleUpdateSocial(social.id, 'url', e.target.value), placeholder: "https://...", className: "flex-1 px-4 py-2 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text" }), _jsx("button", { onClick: () => handleRemoveSocial(social.id), className: "px-4 py-2 text-xs font-bold text-red-500 hover:text-red-700 dark:hover:text-red-400 transition-colors", children: "Remove" })] }, social.id));
186
- })) : (_jsx("p", { className: "text-sm text-dashboard-text-secondary text-center py-8", children: "No social links added yet. Click \"Add Social\" to get started." })) })] })] }), _jsxs("div", { className: "space-y-8", children: [_jsxs("section", { className: "bg-dashboard-bg p-6 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Settings2, { size: 18, className: "text-primary" }), "Maintenance"] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text block mb-1", children: "Maintenance Mode" }), _jsx("p", { className: "text-[10px] text-dashboard-text-secondary", children: "Show maintenance page to visitors" })] }), _jsx("button", { onClick: () => setSettings({ ...settings, maintenanceMode: !settings.maintenanceMode }), className: `relative w-12 h-6 rounded-full transition-colors ${settings.maintenanceMode ? 'bg-primary' : 'bg-neutral-200 dark:bg-neutral-700'}`, children: _jsx("div", { className: `absolute top-1 left-1 w-4 h-4 bg-white rounded-full transition-transform duration-200 ${settings.maintenanceMode ? 'translate-x-6' : 'translate-x-0'}` }) })] })] }), _jsxs("section", { className: "bg-dashboard-bg p-6 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Calendar, { size: 18, className: "text-primary" }), "Launch Date"] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text block", children: "Date" }), _jsx("input", { type: "date", value: settings.launch_date ? settings.launch_date.split('T')[0] : '', onChange: (e) => {
241
+ : 'bg-primary text-white hover:bg-primary/90'}`, children: isSaving ? (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "w-4 h-4 animate-spin" }), "Saving..."] })) : showSuccess ? (_jsxs(_Fragment, { children: [_jsx(Settings2, { className: "w-4 h-4" }), "Saved!"] })) : (_jsxs(_Fragment, { children: [_jsx(Save, { className: "w-4 h-4" }), "Save Settings"] })) })] }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-8", children: [_jsxs("div", { className: "lg:col-span-2 space-y-8", children: [_jsxs("section", { className: "bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Search, { size: 20, className: "text-primary" }), "Website Identity & SEO"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Website Name" }), _jsx("input", { type: "text", value: settings.siteName || '', onChange: (e) => setSettings({ ...settings, siteName: e.target.value }), placeholder: "e.g., Botanics & You", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Website Tagline" }), _jsx("input", { type: "text", value: settings.siteTagline || '', onChange: (e) => setSettings({ ...settings, siteTagline: e.target.value }), placeholder: "e.g., Sharing my knowledge with you", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] })] }), _jsxs("div", { className: "mt-6 space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Website Description" }), _jsx("textarea", { value: settings.siteDescription || '', onChange: (e) => setSettings({ ...settings, siteDescription: e.target.value }), placeholder: "A brief description of your website", rows: 3, className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text resize-none" })] }), _jsxs("div", { className: "mt-6 space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Keywords (comma-separated)" }), _jsx("input", { type: "text", value: settings.keywords || '', onChange: (e) => setSettings({ ...settings, keywords: e.target.value }), placeholder: "keyword1, keyword2, keyword3", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] })] }), _jsxs("section", { className: "bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Mail, { size: 20, className: "text-primary" }), "Contact Information"] }), _jsx("div", { className: "flex gap-2 mb-6", children: AVAILABLE_LOCALES.map((loc) => (_jsxs("button", { onClick: () => setActiveTab(loc.code), className: `px-4 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all ${activeTab === loc.code
242
+ ? 'bg-primary text-white'
243
+ : 'bg-dashboard-card text-dashboard-text-secondary hover:bg-dashboard-border'}`, children: [_jsx("span", { className: "mr-1", children: loc.flag }), loc.code.toUpperCase()] }, loc.code))) }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: "Contact Email (global)" }), _jsx("input", { type: "email", value: settings.contactEmail || '', onChange: (e) => setSettings({ ...settings, contactEmail: e.target.value }), placeholder: "contact@example.com", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: ["Phone Number (", activeTab.toUpperCase(), ")"] }), _jsx("input", { type: "tel", value: settings.localizedContactInfo?.[activeTab]?.phoneNumber || settings.phoneNumber || '', onChange: (e) => handleUpdateLocalizedContact('phoneNumber', e.target.value), placeholder: "+31 6 12345678", className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text" })] })] }), _jsxs("div", { className: "mt-6 space-y-2", children: [_jsxs("label", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest", children: ["Physical Address (", activeTab.toUpperCase(), ")"] }), _jsx("textarea", { value: settings.localizedContactInfo?.[activeTab]?.physicalAddress || settings.physicalAddress || '', onChange: (e) => handleUpdateLocalizedContact('physicalAddress', e.target.value), placeholder: "Street address, City, Country", rows: 2, className: "w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text resize-none" })] })] }), _jsxs("section", { className: "bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-dashboard-border pb-4 mb-6", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text", children: [_jsx(Globe, { size: 20, className: "text-primary" }), "Social Links (", activeTab.toUpperCase(), ")"] }), _jsx("button", { onClick: handleAddLocalizedSocial, className: "px-4 py-2 text-xs font-bold uppercase tracking-widest bg-primary text-white rounded-full hover:bg-primary/90 transition-all", children: "Add Social" })] }), _jsx("div", { className: "flex gap-2 mb-6", children: AVAILABLE_LOCALES.map((loc) => (_jsxs("button", { onClick: () => setActiveTab(loc.code), className: `px-4 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all ${activeTab === loc.code
244
+ ? 'bg-primary text-white'
245
+ : 'bg-dashboard-card text-dashboard-text-secondary hover:bg-dashboard-border'}`, children: [_jsx("span", { className: "mr-1", children: loc.flag }), loc.code.toUpperCase()] }, loc.code))) }), _jsx("div", { className: "space-y-4", children: (() => {
246
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
247
+ return currentSocials.length > 0 ? (currentSocials.map((social) => {
248
+ const platform = AVAILABLE_PLATFORMS.find(p => p.name === social.platform);
249
+ return (_jsxs("div", { className: "flex items-center gap-4 p-4 bg-dashboard-card rounded-2xl border border-dashboard-border", children: [_jsx("div", { className: "flex-shrink-0 text-dashboard-text-secondary", children: platform?.icon || _jsx(Globe, { size: 18 }) }), _jsxs("select", { value: social.platform, onChange: (e) => handleUpdateLocalizedSocial(social.id, 'platform', e.target.value), className: "flex-1 px-4 py-2 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text", children: [_jsx("option", { value: "", children: "Select Platform" }), AVAILABLE_PLATFORMS.map(p => (_jsx("option", { value: p.name, children: p.name }, p.name)))] }), _jsx("input", { type: "url", value: social.url, onChange: (e) => handleUpdateLocalizedSocial(social.id, 'url', e.target.value), placeholder: "https://...", className: "flex-1 px-4 py-2 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text" }), _jsx("button", { onClick: () => handleRemoveLocalizedSocial(social.id), className: "px-4 py-2 text-xs font-bold text-red-500 hover:text-red-700 dark:hover:text-red-400 transition-colors", children: "Remove" })] }, social.id));
250
+ })) : (_jsxs("p", { className: "text-sm text-dashboard-text-secondary text-center py-8", children: ["No social links added for ", activeTab.toUpperCase(), ". Click \"Add Social\" to get started."] }));
251
+ })() })] })] }), _jsxs("div", { className: "space-y-8", children: [_jsxs("section", { className: "bg-dashboard-bg p-6 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Settings2, { size: 18, className: "text-primary" }), "Maintenance"] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text block mb-1", children: "Maintenance Mode" }), _jsx("p", { className: "text-[10px] text-dashboard-text-secondary", children: "Show maintenance page to visitors" })] }), _jsx("button", { onClick: () => setSettings({ ...settings, maintenanceMode: !settings.maintenanceMode }), className: `relative w-12 h-6 rounded-full transition-colors ${settings.maintenanceMode ? 'bg-primary' : 'bg-neutral-200 dark:bg-neutral-700'}`, children: _jsx("div", { className: `absolute top-1 left-1 w-4 h-4 bg-white rounded-full transition-transform duration-200 ${settings.maintenanceMode ? 'translate-x-6' : 'translate-x-0'}` }) })] })] }), _jsxs("section", { className: "bg-dashboard-bg p-6 rounded-3xl border border-dashboard-border", children: [_jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text border-b border-dashboard-border pb-4 mb-6", children: [_jsx(Calendar, { size: 18, className: "text-primary" }), "Launch Date"] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text block", children: "Date" }), _jsx("input", { type: "date", value: settings.launch_date ? settings.launch_date.split('T')[0] : '', onChange: (e) => {
187
252
  const dateValue = e.target.value;
188
253
  const currentTime = settings.launch_date?.includes('T')
189
254
  ? settings.launch_date.split('T')[1]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jhits/plugin-website",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Website management and configuration plugin for the JHITS ecosystem",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -40,6 +40,16 @@ export async function GET_SETTINGS(
40
40
  maintenanceMode: false,
41
41
  launch_date: '',
42
42
  socials: [],
43
+ localizedContactInfo: {
44
+ en: { physicalAddress: '', phoneNumber: '' },
45
+ sv: { physicalAddress: '', phoneNumber: '' },
46
+ nl: { physicalAddress: '', phoneNumber: '' },
47
+ },
48
+ localizedSocials: {
49
+ en: [],
50
+ sv: [],
51
+ nl: [],
52
+ },
43
53
  });
44
54
  }
45
55
 
@@ -2,6 +2,19 @@
2
2
  * Website Settings Types
3
3
  */
4
4
 
5
+ export type SupportedLocale = 'en' | 'sv' | 'nl';
6
+
7
+ export interface LocalizedContactInfo {
8
+ physicalAddress?: string;
9
+ phoneNumber?: string;
10
+ }
11
+
12
+ export interface LocalizedSocialLink {
13
+ id: number;
14
+ platform: string;
15
+ url: string;
16
+ }
17
+
5
18
  export interface WebsiteSettings {
6
19
  identifier: string;
7
20
  siteName?: string;
@@ -15,6 +28,8 @@ export interface WebsiteSettings {
15
28
  maintenanceMode?: boolean;
16
29
  launch_date?: string;
17
30
  socials?: SocialLink[];
31
+ localizedContactInfo?: Partial<Record<SupportedLocale, LocalizedContactInfo>>;
32
+ localizedSocials?: Partial<Record<SupportedLocale, LocalizedSocialLink[]>>;
18
33
  updatedAt?: Date;
19
34
  createdAt?: Date;
20
35
  }
@@ -7,10 +7,16 @@
7
7
 
8
8
  import React, { useState, useEffect, useRef } from 'react';
9
9
  import { Save, RefreshCw, Globe, Mail, Phone, MapPin, Search, Settings2, Calendar } from 'lucide-react';
10
- import { WebsiteSettings, SocialLink } from '../types/settings';
10
+ import { WebsiteSettings, SocialLink, SupportedLocale, LocalizedSocialLink } from '../types/settings';
11
11
  import { FaFacebook, FaInstagram, FaLinkedin, FaPinterest, FaTiktok } from 'react-icons/fa';
12
12
  import { FaXTwitter } from 'react-icons/fa6';
13
13
 
14
+ const AVAILABLE_LOCALES: { code: SupportedLocale; name: string; flag: string }[] = [
15
+ { code: 'en', name: 'English', flag: 'πŸ‡¬πŸ‡§' },
16
+ { code: 'sv', name: 'Swedish', flag: 'πŸ‡ΈπŸ‡ͺ' },
17
+ { code: 'nl', name: 'Dutch', flag: 'πŸ‡³πŸ‡±' },
18
+ ];
19
+
14
20
  const AVAILABLE_PLATFORMS = [
15
21
  { name: 'Instagram', icon: <FaInstagram size={18} /> },
16
22
  { name: 'Facebook', icon: <FaFacebook size={18} /> },
@@ -29,6 +35,7 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
29
35
  const [isLoading, setIsLoading] = useState(true);
30
36
  const [isSaving, setIsSaving] = useState(false);
31
37
  const [showSuccess, setShowSuccess] = useState(false);
38
+ const [activeTab, setActiveTab] = useState<SupportedLocale>('en');
32
39
  const [settings, setSettings] = useState<WebsiteSettings>({
33
40
  identifier: 'site_config',
34
41
  siteName: '',
@@ -42,6 +49,16 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
42
49
  maintenanceMode: false,
43
50
  launch_date: '',
44
51
  socials: [],
52
+ localizedContactInfo: {
53
+ en: { physicalAddress: '', phoneNumber: '' },
54
+ sv: { physicalAddress: '', phoneNumber: '' },
55
+ nl: { physicalAddress: '', phoneNumber: '' },
56
+ },
57
+ localizedSocials: {
58
+ en: [],
59
+ sv: [],
60
+ nl: [],
61
+ },
45
62
  });
46
63
 
47
64
  // Fetch settings on load
@@ -96,6 +113,16 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
96
113
  maintenanceMode: data.maintenanceMode ?? false,
97
114
  launch_date: launchDate,
98
115
  socials: data.socials || [],
116
+ localizedContactInfo: data.localizedContactInfo || {
117
+ en: { physicalAddress: '', phoneNumber: '' },
118
+ sv: { physicalAddress: '', phoneNumber: '' },
119
+ nl: { physicalAddress: '', phoneNumber: '' },
120
+ },
121
+ localizedSocials: data.localizedSocials || {
122
+ en: [],
123
+ sv: [],
124
+ nl: [],
125
+ },
99
126
  });
100
127
  }
101
128
  } catch (error) {
@@ -164,30 +191,64 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
164
191
  }
165
192
  };
166
193
 
167
- // Add social link
168
- const handleAddSocial = () => {
169
- const newId = settings.socials?.length ? Math.max(...settings.socials.map(s => s.id)) + 1 : 1;
194
+ // Remove social link
195
+ const handleRemoveSocial = (id: number) => {
170
196
  setSettings({
171
197
  ...settings,
172
- socials: [...(settings.socials || []), { id: newId, platform: '', url: '' }],
198
+ socials: settings.socials?.filter(social => social.id !== id) || [],
173
199
  });
174
200
  };
175
201
 
176
- // Update social link
177
- const handleUpdateSocial = (id: number, field: 'platform' | 'url', value: string) => {
202
+ // Update localized contact info
203
+ const handleUpdateLocalizedContact = (field: 'physicalAddress' | 'phoneNumber', value: string) => {
178
204
  setSettings({
179
205
  ...settings,
180
- socials: settings.socials?.map(social =>
181
- social.id === id ? { ...social, [field]: value } : social
182
- ) || [],
206
+ localizedContactInfo: {
207
+ ...settings.localizedContactInfo,
208
+ [activeTab]: {
209
+ ...settings.localizedContactInfo?.[activeTab],
210
+ [field]: value,
211
+ },
212
+ },
183
213
  });
184
214
  };
185
215
 
186
- // Remove social link
187
- const handleRemoveSocial = (id: number) => {
216
+ // Add localized social link
217
+ const handleAddLocalizedSocial = () => {
218
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
219
+ const newId = currentSocials.length ? Math.max(...currentSocials.map(s => s.id)) + 1 : 1;
188
220
  setSettings({
189
221
  ...settings,
190
- socials: settings.socials?.filter(social => social.id !== id) || [],
222
+ localizedSocials: {
223
+ ...settings.localizedSocials,
224
+ [activeTab]: [...currentSocials, { id: newId, platform: '', url: '' }],
225
+ },
226
+ });
227
+ };
228
+
229
+ // Update localized social link
230
+ const handleUpdateLocalizedSocial = (id: number, field: 'platform' | 'url', value: string) => {
231
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
232
+ setSettings({
233
+ ...settings,
234
+ localizedSocials: {
235
+ ...settings.localizedSocials,
236
+ [activeTab]: currentSocials.map(social =>
237
+ social.id === id ? { ...social, [field]: value } : social
238
+ ),
239
+ },
240
+ });
241
+ };
242
+
243
+ // Remove localized social link
244
+ const handleRemoveLocalizedSocial = (id: number) => {
245
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
246
+ setSettings({
247
+ ...settings,
248
+ localizedSocials: {
249
+ ...settings.localizedSocials,
250
+ [activeTab]: currentSocials.filter(social => social.id !== id),
251
+ },
191
252
  });
192
253
  };
193
254
 
@@ -311,10 +372,29 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
311
372
  <Mail size={20} className="text-primary" />
312
373
  Contact Information
313
374
  </div>
375
+
376
+ {/* Language Tabs */}
377
+ <div className="flex gap-2 mb-6">
378
+ {AVAILABLE_LOCALES.map((loc) => (
379
+ <button
380
+ key={loc.code}
381
+ onClick={() => setActiveTab(loc.code)}
382
+ className={`px-4 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all ${
383
+ activeTab === loc.code
384
+ ? 'bg-primary text-white'
385
+ : 'bg-dashboard-card text-dashboard-text-secondary hover:bg-dashboard-border'
386
+ }`}
387
+ >
388
+ <span className="mr-1">{loc.flag}</span>
389
+ {loc.code.toUpperCase()}
390
+ </button>
391
+ ))}
392
+ </div>
393
+
314
394
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
315
395
  <div className="space-y-2">
316
396
  <label className="text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest">
317
- Contact Email
397
+ Contact Email (global)
318
398
  </label>
319
399
  <input
320
400
  type="email"
@@ -326,12 +406,12 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
326
406
  </div>
327
407
  <div className="space-y-2">
328
408
  <label className="text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest">
329
- Phone Number
409
+ Phone Number ({activeTab.toUpperCase()})
330
410
  </label>
331
411
  <input
332
412
  type="tel"
333
- value={settings.phoneNumber || ''}
334
- onChange={(e) => setSettings({ ...settings, phoneNumber: e.target.value })}
413
+ value={settings.localizedContactInfo?.[activeTab]?.phoneNumber || settings.phoneNumber || ''}
414
+ onChange={(e) => handleUpdateLocalizedContact('phoneNumber', e.target.value)}
335
415
  placeholder="+31 6 12345678"
336
416
  className="w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text"
337
417
  />
@@ -339,11 +419,11 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
339
419
  </div>
340
420
  <div className="mt-6 space-y-2">
341
421
  <label className="text-xs font-bold text-dashboard-text-secondary uppercase tracking-widest">
342
- Physical Address
422
+ Physical Address ({activeTab.toUpperCase()})
343
423
  </label>
344
424
  <textarea
345
- value={settings.physicalAddress || ''}
346
- onChange={(e) => setSettings({ ...settings, physicalAddress: e.target.value })}
425
+ value={settings.localizedContactInfo?.[activeTab]?.physicalAddress || settings.physicalAddress || ''}
426
+ onChange={(e) => handleUpdateLocalizedContact('physicalAddress', e.target.value)}
347
427
  placeholder="Street address, City, Country"
348
428
  rows={2}
349
429
  className="w-full px-4 py-3 bg-dashboard-card border border-dashboard-border rounded-2xl outline-none focus:ring-2 focus:ring-primary transition-all text-dashboard-text resize-none"
@@ -351,23 +431,44 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
351
431
  </div>
352
432
  </section>
353
433
 
354
- {/* Social Links */}
434
+ {/* Social Links (Localized) */}
355
435
  <section className="bg-dashboard-bg p-8 rounded-3xl border border-dashboard-border">
356
436
  <div className="flex items-center justify-between border-b border-dashboard-border pb-4 mb-6">
357
437
  <div className="flex items-center gap-2 font-bold text-dashboard-text">
358
438
  <Globe size={20} className="text-primary" />
359
- Social Links
439
+ Social Links ({activeTab.toUpperCase()})
360
440
  </div>
361
441
  <button
362
- onClick={handleAddSocial}
442
+ onClick={handleAddLocalizedSocial}
363
443
  className="px-4 py-2 text-xs font-bold uppercase tracking-widest bg-primary text-white rounded-full hover:bg-primary/90 transition-all"
364
444
  >
365
445
  Add Social
366
446
  </button>
367
447
  </div>
448
+
449
+ {/* Language Tabs for Socials */}
450
+ <div className="flex gap-2 mb-6">
451
+ {AVAILABLE_LOCALES.map((loc) => (
452
+ <button
453
+ key={loc.code}
454
+ onClick={() => setActiveTab(loc.code)}
455
+ className={`px-4 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all ${
456
+ activeTab === loc.code
457
+ ? 'bg-primary text-white'
458
+ : 'bg-dashboard-card text-dashboard-text-secondary hover:bg-dashboard-border'
459
+ }`}
460
+ >
461
+ <span className="mr-1">{loc.flag}</span>
462
+ {loc.code.toUpperCase()}
463
+ </button>
464
+ ))}
465
+ </div>
466
+
368
467
  <div className="space-y-4">
369
- {settings.socials && settings.socials.length > 0 ? (
370
- settings.socials.map((social) => {
468
+ {(() => {
469
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
470
+ return currentSocials.length > 0 ? (
471
+ currentSocials.map((social) => {
371
472
  const platform = AVAILABLE_PLATFORMS.find(p => p.name === social.platform);
372
473
  return (
373
474
  <div key={social.id} className="flex items-center gap-4 p-4 bg-dashboard-card rounded-2xl border border-dashboard-border">
@@ -376,7 +477,7 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
376
477
  </div>
377
478
  <select
378
479
  value={social.platform}
379
- onChange={(e) => handleUpdateSocial(social.id, 'platform', e.target.value)}
480
+ onChange={(e) => handleUpdateLocalizedSocial(social.id, 'platform', e.target.value)}
380
481
  className="flex-1 px-4 py-2 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text"
381
482
  >
382
483
  <option value="">Select Platform</option>
@@ -387,12 +488,12 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
387
488
  <input
388
489
  type="url"
389
490
  value={social.url}
390
- onChange={(e) => handleUpdateSocial(social.id, 'url', e.target.value)}
491
+ onChange={(e) => handleUpdateLocalizedSocial(social.id, 'url', e.target.value)}
391
492
  placeholder="https://..."
392
493
  className="flex-1 px-4 py-2 bg-dashboard-bg border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text"
393
494
  />
394
495
  <button
395
- onClick={() => handleRemoveSocial(social.id)}
496
+ onClick={() => handleRemoveLocalizedSocial(social.id)}
396
497
  className="px-4 py-2 text-xs font-bold text-red-500 hover:text-red-700 dark:hover:text-red-400 transition-colors"
397
498
  >
398
499
  Remove
@@ -402,9 +503,10 @@ export function SettingsView({ siteId, locale }: SettingsViewProps) {
402
503
  })
403
504
  ) : (
404
505
  <p className="text-sm text-dashboard-text-secondary text-center py-8">
405
- No social links added yet. Click "Add Social" to get started.
506
+ No social links added for {activeTab.toUpperCase()}. Click "Add Social" to get started.
406
507
  </p>
407
- )}
508
+ );
509
+ })()}
408
510
  </div>
409
511
  </section>
410
512
  </div>