@jhits/plugin-website 0.0.12 β†’ 0.0.14

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,21 @@
1
1
  /**
2
2
  * Website Settings Types
3
3
  */
4
+ export type SupportedLocale = 'en' | 'sv' | 'nl';
5
+ export interface DomainLocaleConfig {
6
+ domain: string;
7
+ locale: SupportedLocale;
8
+ allowUserOverride?: boolean;
9
+ }
10
+ export interface LocalizedContactInfo {
11
+ physicalAddress?: string;
12
+ phoneNumber?: string;
13
+ }
14
+ export interface LocalizedSocialLink {
15
+ id: number;
16
+ platform: string;
17
+ url: string;
18
+ }
4
19
  export interface WebsiteSettings {
5
20
  identifier: string;
6
21
  siteName?: string;
@@ -14,6 +29,9 @@ export interface WebsiteSettings {
14
29
  maintenanceMode?: boolean;
15
30
  launch_date?: string;
16
31
  socials?: SocialLink[];
32
+ localizedContactInfo?: Partial<Record<SupportedLocale, LocalizedContactInfo>>;
33
+ localizedSocials?: Partial<Record<SupportedLocale, LocalizedSocialLink[]>>;
34
+ domainLocaleConfig?: DomainLocaleConfig[];
17
35
  updatedAt?: Date;
18
36
  createdAt?: Date;
19
37
  }
@@ -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,kBAAkB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,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,kBAAkB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC1C,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;AAyMD,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,iBAAiB,2CAmdjE"}
@@ -5,9 +5,14 @@
5
5
  'use client';
6
6
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
7
7
  import { useState, useEffect, useRef } from 'react';
8
- import { Save, RefreshCw, Globe, Mail, Search, Settings2, Calendar } from 'lucide-react';
8
+ import { Save, RefreshCw, Globe, Globe2, Mail, Search, Settings2, Calendar, Plus, Trash2, X, Edit3 } 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 }) },
@@ -16,10 +21,46 @@ const AVAILABLE_PLATFORMS = [
16
21
  { name: 'LinkedIn', icon: _jsx(FaLinkedin, { size: 18 }) },
17
22
  { name: 'TikTok', icon: _jsx(FaTiktok, { size: 18 }) },
18
23
  ];
24
+ function DomainLanguagesCard({ config, onEdit }) {
25
+ return (_jsxs("section", { className: "bg-dashboard-bg p-6 rounded-3xl border border-dashboard-border", children: [_jsx("div", { className: "flex items-center justify-between border-b border-dashboard-border pb-4 mb-4", children: _jsxs("div", { className: "flex items-center gap-2 font-bold text-dashboard-text", children: [_jsx(Globe2, { size: 18, className: "text-primary" }), "Domain Languages"] }) }), _jsx("div", { className: "space-y-2", children: config && config.length > 0 ? (_jsx("div", { className: "flex flex-wrap gap-2", children: config.map((entry, index) => (_jsxs("div", { className: "inline-flex items-center gap-2 px-3 py-1.5 bg-dashboard-card rounded-full border border-dashboard-border text-xs", children: [_jsx("span", { className: "font-medium text-dashboard-text", children: entry.domain }), _jsx("span", { className: "text-dashboard-text-secondary", children: "\u2192" }), _jsx("span", { children: AVAILABLE_LOCALES.find(l => l.code === entry.locale)?.flag }), _jsx("span", { className: "text-dashboard-text-secondary", children: entry.allowUserOverride ? '' : 'πŸ”’' })] }, index))) })) : (_jsx("p", { className: "text-xs text-dashboard-text-secondary", children: "No domain languages configured." })) }), _jsxs("button", { onClick: onEdit, className: "mt-4 w-full flex items-center justify-center gap-2 px-4 py-2 bg-primary text-white rounded-xl text-xs font-bold uppercase tracking-wider hover:bg-primary/90 transition-colors", children: [_jsx(Edit3, { size: 14 }), config?.length ? 'Edit Domains' : 'Add Domains'] })] }));
26
+ }
27
+ function DomainLanguagesModal({ isOpen, config, onSave, onClose }) {
28
+ const [tempConfig, setTempConfig] = useState(config);
29
+ const [expandedIndex, setExpandedIndex] = useState(null);
30
+ useEffect(() => {
31
+ setTempConfig(config);
32
+ setExpandedIndex(null);
33
+ }, [config, isOpen]);
34
+ if (!isOpen)
35
+ return null;
36
+ const handleAdd = () => {
37
+ setTempConfig([...tempConfig, { domain: '', locale: 'en', allowUserOverride: true }]);
38
+ setExpandedIndex(tempConfig.length);
39
+ };
40
+ const handleUpdate = (index, field, value) => {
41
+ const updated = [...tempConfig];
42
+ updated[index] = { ...updated[index], [field]: value };
43
+ setTempConfig(updated);
44
+ };
45
+ const handleRemove = (index) => {
46
+ setTempConfig(tempConfig.filter((_, i) => i !== index));
47
+ if (expandedIndex === index)
48
+ setExpandedIndex(null);
49
+ };
50
+ const toggleExpand = (index) => {
51
+ setExpandedIndex(expandedIndex === index ? null : index);
52
+ };
53
+ return (_jsx("div", { className: "fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4", children: _jsxs("div", { className: "bg-dashboard-bg rounded-3xl border border-dashboard-border w-full max-w-lg max-h-[80vh] overflow-hidden flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between p-6 border-b border-dashboard-border", children: [_jsx("h2", { className: "text-xl font-bold text-dashboard-text", children: "Domain Languages" }), _jsx("button", { onClick: onClose, className: "p-2 text-dashboard-text-secondary hover:text-dashboard-text transition-colors", children: _jsx(X, { size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto p-6 space-y-4", children: [tempConfig.length > 0 && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-wider", children: "Current Config" }), tempConfig.map((entry, index) => (_jsxs("div", { className: "bg-dashboard-card rounded-xl border border-dashboard-border overflow-hidden", children: [_jsxs("div", { onClick: () => toggleExpand(index), className: "w-full flex items-center justify-between p-3 text-left hover:bg-dashboard-border/50 transition-colors cursor-pointer", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-medium text-dashboard-text", children: entry.domain || '(no domain)' }), _jsx("span", { className: "text-dashboard-text-secondary", children: "\u2192" }), _jsx("span", { children: AVAILABLE_LOCALES.find(l => l.code === entry.locale)?.flag }), entry.allowUserOverride === false && _jsx("span", { className: "text-dashboard-text-secondary", children: "\uD83D\uDD12" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { onClick: (e) => { e.stopPropagation(); handleRemove(index); }, className: "p-1 text-red-500 hover:bg-red-500/10 rounded transition-colors", title: "Remove", children: _jsx(Trash2, { size: 14 }) }), _jsx("span", { className: "text-dashboard-text-secondary text-xs", children: expandedIndex === index ? 'β–²' : 'β–Ό' })] })] }), expandedIndex === index && (_jsxs("div", { className: "p-3 pt-0 space-y-3 border-t border-dashboard-border", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-[10px] font-bold text-dashboard-text-secondary uppercase tracking-wider", children: "Domain" }), _jsx("input", { type: "text", value: entry.domain, onChange: (e) => handleUpdate(index, 'domain', e.target.value), placeholder: "example.com", className: "w-full px-3 py-2 bg-dashboard-bg border border-dashboard-border rounded-lg outline-none focus:ring-2 focus:ring-primary text-dashboard-text text-sm" })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("div", { className: "flex-1 space-y-1", children: [_jsx("label", { className: "text-[10px] font-bold text-dashboard-text-secondary uppercase tracking-wider", children: "Language" }), _jsx("select", { value: entry.locale, onChange: (e) => handleUpdate(index, 'locale', e.target.value), className: "w-full px-3 py-2 bg-dashboard-bg border border-dashboard-border rounded-lg outline-none focus:ring-2 focus:ring-primary text-dashboard-text text-sm", children: AVAILABLE_LOCALES.map(loc => (_jsxs("option", { value: loc.code, children: [loc.flag, " ", loc.name] }, loc.code))) })] }) }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-[10px] text-dashboard-text-secondary", children: "Allow user to change" }), _jsx("button", { onClick: () => handleUpdate(index, 'allowUserOverride', !entry.allowUserOverride), className: `relative w-10 h-5 rounded-full transition-colors ${entry.allowUserOverride ? 'bg-primary' : 'bg-neutral-300 dark:bg-neutral-600'}`, children: _jsx("div", { className: `absolute top-0.5 left-0.5 w-4 h-4 bg-white rounded-full transition-transform duration-200 ${entry.allowUserOverride ? 'translate-x-5' : 'translate-x-0'}` }) })] })] }))] }, index)))] })), _jsxs("div", { className: "border-t border-dashboard-border pt-4", children: [_jsx("p", { className: "text-xs font-bold text-dashboard-text-secondary uppercase tracking-wider mb-3", children: "Add New Domain" }), _jsxs("button", { onClick: handleAdd, className: "w-full flex items-center justify-center gap-2 px-4 py-3 border-2 border-dashed border-dashboard-border text-dashboard-text-secondary hover:border-primary hover:text-primary rounded-xl transition-colors", children: [_jsx(Plus, { size: 16 }), "Add Domain"] })] }), _jsx("p", { className: "text-[10px] text-dashboard-text-secondary text-center pt-2", children: "Configure which language to use per domain. E.g., botanicsandyou.nl \u2192 Dutch, botanicsandyou.se \u2192 Swedish." })] }), _jsxs("div", { className: "flex gap-3 p-6 border-t border-dashboard-border", children: [_jsx("button", { onClick: onClose, className: "flex-1 px-4 py-2 bg-dashboard-card text-dashboard-text rounded-xl text-sm font-bold hover:bg-dashboard-border transition-colors", children: "Cancel" }), _jsx("button", { onClick: () => onSave(tempConfig), className: "flex-1 px-4 py-2 bg-primary text-white rounded-xl text-sm font-bold hover:bg-primary/90 transition-colors", children: "Save" })] })] }) }));
54
+ }
55
+ // =============================================================================
56
+ // Main Component
57
+ // =============================================================================
19
58
  export function SettingsView({ siteId, locale }) {
20
59
  const [isLoading, setIsLoading] = useState(true);
21
60
  const [isSaving, setIsSaving] = useState(false);
22
61
  const [showSuccess, setShowSuccess] = useState(false);
62
+ const [activeTab, setActiveTab] = useState('en');
63
+ const [showDomainModal, setShowDomainModal] = useState(false);
23
64
  const [settings, setSettings] = useState({
24
65
  identifier: 'site_config',
25
66
  siteName: '',
@@ -33,27 +74,32 @@ export function SettingsView({ siteId, locale }) {
33
74
  maintenanceMode: false,
34
75
  launch_date: '',
35
76
  socials: [],
77
+ localizedContactInfo: {
78
+ en: { physicalAddress: '', phoneNumber: '' },
79
+ sv: { physicalAddress: '', phoneNumber: '' },
80
+ nl: { physicalAddress: '', phoneNumber: '' },
81
+ },
82
+ localizedSocials: {
83
+ en: [],
84
+ sv: [],
85
+ nl: [],
86
+ },
87
+ domainLocaleConfig: [],
36
88
  });
37
89
  // Fetch settings on load
38
90
  useEffect(() => {
39
91
  const fetchSettings = async () => {
40
92
  try {
41
93
  setIsLoading(true);
42
- const response = await fetch('/api/plugin-website/settings', {
43
- credentials: 'include',
44
- });
45
- if (!response.ok) {
94
+ const response = await fetch('/api/plugin-website/settings', { credentials: 'include' });
95
+ if (!response.ok)
46
96
  throw new Error('Failed to fetch settings');
47
- }
48
97
  const data = await response.json();
49
98
  if (data.siteName !== undefined) {
50
- // Convert launch_date to datetime-local format if it exists
51
99
  let launchDate = '';
52
100
  if (data.launch_date) {
53
- // If it's a Date object or ISO string, convert to datetime-local format
54
101
  const date = new Date(data.launch_date);
55
102
  if (!isNaN(date.getTime())) {
56
- // Format as YYYY-MM-DDTHH:mm for datetime-local input (24-hour format)
57
103
  const year = date.getFullYear();
58
104
  const month = String(date.getMonth() + 1).padStart(2, '0');
59
105
  const day = String(date.getDate()).padStart(2, '0');
@@ -61,19 +107,6 @@ export function SettingsView({ siteId, locale }) {
61
107
  const minutes = String(date.getMinutes()).padStart(2, '0');
62
108
  launchDate = `${year}-${month}-${day}T${hours}:${minutes}`;
63
109
  }
64
- else {
65
- // If it's already a string in the correct format, use it
66
- // Ensure it has time component, default to 00:00 if missing
67
- if (data.launch_date.includes('T') && data.launch_date.split('T')[1]) {
68
- launchDate = data.launch_date;
69
- }
70
- else if (data.launch_date.includes('T')) {
71
- launchDate = `${data.launch_date.split('T')[0]}T00:00`;
72
- }
73
- else {
74
- launchDate = `${data.launch_date}T00:00`;
75
- }
76
- }
77
110
  }
78
111
  setSettings({
79
112
  identifier: 'site_config',
@@ -88,6 +121,13 @@ export function SettingsView({ siteId, locale }) {
88
121
  maintenanceMode: data.maintenanceMode ?? false,
89
122
  launch_date: launchDate,
90
123
  socials: data.socials || [],
124
+ localizedContactInfo: data.localizedContactInfo || {
125
+ en: { physicalAddress: '', phoneNumber: '' },
126
+ sv: { physicalAddress: '', phoneNumber: '' },
127
+ nl: { physicalAddress: '', phoneNumber: '' },
128
+ },
129
+ localizedSocials: data.localizedSocials || { en: [], sv: [], nl: [] },
130
+ domainLocaleConfig: data.domainLocaleConfig || [],
91
131
  });
92
132
  }
93
133
  }
@@ -102,34 +142,19 @@ export function SettingsView({ siteId, locale }) {
102
142
  }, []);
103
143
  // Use ref to always get latest state
104
144
  const settingsRef = useRef(settings);
105
- useEffect(() => {
106
- settingsRef.current = settings;
107
- }, [settings]);
145
+ useEffect(() => { settingsRef.current = settings; }, [settings]);
108
146
  // Save settings
109
147
  const handleSave = async () => {
110
148
  try {
111
149
  setIsSaving(true);
112
- // Get the latest state from ref
113
150
  const currentSettings = settingsRef.current;
114
- // Prepare settings for API - ensure launch_date is properly formatted
115
- const settingsToSave = {
116
- ...currentSettings,
117
- };
118
- // Handle launch_date - keep it if it has a value, otherwise don't include it
151
+ const settingsToSave = { ...currentSettings };
119
152
  if (currentSettings.launch_date && currentSettings.launch_date.trim() !== '') {
120
153
  settingsToSave.launch_date = currentSettings.launch_date;
121
154
  }
122
155
  else {
123
- // Don't include launch_date if it's empty
124
156
  delete settingsToSave.launch_date;
125
157
  }
126
- console.log('[SettingsView] Saving settings:', {
127
- launch_date: settingsToSave.launch_date,
128
- launch_date_type: typeof settingsToSave.launch_date,
129
- has_launch_date: 'launch_date' in settingsToSave,
130
- currentState_launch_date: currentSettings.launch_date,
131
- all_keys: Object.keys(settingsToSave),
132
- });
133
158
  const response = await fetch('/api/plugin-website/settings', {
134
159
  method: 'POST',
135
160
  headers: { 'Content-Type': 'application/json' },
@@ -151,69 +176,75 @@ export function SettingsView({ siteId, locale }) {
151
176
  setIsSaving(false);
152
177
  }
153
178
  };
154
- // Add social link
155
- const handleAddSocial = () => {
156
- const newId = settings.socials?.length ? Math.max(...settings.socials.map(s => s.id)) + 1 : 1;
179
+ // Update localized contact info
180
+ const handleUpdateLocalizedContact = (field, value) => {
181
+ setSettings({
182
+ ...settings,
183
+ localizedContactInfo: {
184
+ ...settings.localizedContactInfo,
185
+ [activeTab]: { ...settings.localizedContactInfo?.[activeTab], [field]: value },
186
+ },
187
+ });
188
+ };
189
+ // Social links handlers
190
+ const handleAddLocalizedSocial = () => {
191
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
192
+ const newId = currentSocials.length ? Math.max(...currentSocials.map(s => s.id)) + 1 : 1;
157
193
  setSettings({
158
194
  ...settings,
159
- socials: [...(settings.socials || []), { id: newId, platform: '', url: '' }],
195
+ localizedSocials: {
196
+ ...settings.localizedSocials,
197
+ [activeTab]: [...currentSocials, { id: newId, platform: '', url: '' }],
198
+ },
160
199
  });
161
200
  };
162
- // Update social link
163
- const handleUpdateSocial = (id, field, value) => {
201
+ const handleUpdateLocalizedSocial = (id, field, value) => {
202
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
164
203
  setSettings({
165
204
  ...settings,
166
- socials: settings.socials?.map(social => social.id === id ? { ...social, [field]: value } : social) || [],
205
+ localizedSocials: {
206
+ ...settings.localizedSocials,
207
+ [activeTab]: currentSocials.map(s => s.id === id ? { ...s, [field]: value } : s),
208
+ },
167
209
  });
168
210
  };
169
- // Remove social link
170
- const handleRemoveSocial = (id) => {
211
+ const handleRemoveLocalizedSocial = (id) => {
212
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
171
213
  setSettings({
172
214
  ...settings,
173
- socials: settings.socials?.filter(social => social.id !== id) || [],
215
+ localizedSocials: {
216
+ ...settings.localizedSocials,
217
+ [activeTab]: currentSocials.filter(s => s.id !== id),
218
+ },
174
219
  });
175
220
  };
221
+ // Domain locale handlers
222
+ const openDomainModal = () => setShowDomainModal(true);
223
+ const closeDomainModal = () => setShowDomainModal(false);
224
+ const saveDomainConfig = (config) => {
225
+ setSettings({ ...settings, domainLocaleConfig: config });
226
+ setShowDomainModal(false);
227
+ };
176
228
  if (isLoading) {
177
229
  return (_jsx("div", { className: "h-full w-full bg-dashboard-card text-dashboard-text flex items-center justify-center", children: _jsxs("div", { className: "text-center", children: [_jsx(RefreshCw, { className: "w-8 h-8 animate-spin text-primary mx-auto mb-4" }), _jsx("p", { className: "text-sm text-dashboard-text-secondary", children: "Loading settings..." })] }) }));
178
230
  }
179
- return (_jsx("div", { className: "h-full w-full rounded-[2.5rem] bg-dashboard-card p-8 overflow-y-auto", children: _jsxs("div", { className: "max-w-6xl mx-auto", children: [_jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-6 mb-8", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-black text-dashboard-text uppercase tracking-tighter mb-2", children: "Website Settings" }), _jsx("p", { className: "text-sm text-dashboard-text-secondary", children: "Manage your website identity, contact information, and social links" })] }), _jsx("button", { onClick: handleSave, disabled: isSaving, className: `inline-flex items-center gap-2 px-6 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-all shadow-lg shadow-primary/20 ${isSaving
180
- ? 'bg-neutral-400 text-white cursor-not-allowed'
181
- : showSuccess
182
- ? '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) => {
187
- const dateValue = e.target.value;
188
- const currentTime = settings.launch_date?.includes('T')
189
- ? settings.launch_date.split('T')[1]
190
- : '00:00';
191
- const newLaunchDate = dateValue ? `${dateValue}T${currentTime}` : '';
192
- console.log('[SettingsView] Date changed:', {
193
- dateValue,
194
- currentTime,
195
- newLaunchDate,
196
- });
197
- setSettings(prev => ({
198
- ...prev,
199
- launch_date: newLaunchDate,
200
- }));
201
- }, className: "w-full px-4 py-2 bg-dashboard-card border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text block", children: "Time (24-hour format)" }), _jsx("input", { type: "time", step: "60", value: settings.launch_date?.includes('T')
202
- ? settings.launch_date.split('T')[1]
203
- : '00:00', onChange: (e) => {
204
- const timeValue = e.target.value;
205
- const currentDate = settings.launch_date?.includes('T')
206
- ? settings.launch_date.split('T')[0]
207
- : new Date().toISOString().split('T')[0];
208
- const newLaunchDate = timeValue ? `${currentDate}T${timeValue}` : '';
209
- console.log('[SettingsView] Time changed:', {
210
- timeValue,
211
- currentDate,
212
- newLaunchDate,
213
- });
214
- setSettings(prev => ({
215
- ...prev,
216
- launch_date: newLaunchDate,
217
- }));
218
- }, className: "w-full px-4 py-2 bg-dashboard-card border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text" })] }), _jsx("p", { className: "text-[10px] text-dashboard-text-secondary", children: "Used for countdown timers. Time defaults to 00:00 if not specified." })] })] })] })] })] }) }));
231
+ return (_jsxs("div", { className: "h-full w-full rounded-[2.5rem] bg-dashboard-card p-8 overflow-y-auto", children: [_jsxs("div", { className: "max-w-6xl mx-auto", children: [_jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-6 mb-8", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-black text-dashboard-text uppercase tracking-tighter mb-2", children: "Website Settings" }), _jsx("p", { className: "text-sm text-dashboard-text-secondary", children: "Manage your website identity, contact information, and social links" })] }), _jsx("button", { onClick: handleSave, disabled: isSaving, className: `inline-flex items-center gap-2 px-6 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-all shadow-lg shadow-primary/20 ${isSaving ? 'bg-neutral-400 text-white cursor-not-allowed' :
232
+ showSuccess ? 'bg-green-600 text-white' :
233
+ 'bg-primary text-white hover:bg-primary/90'}`, children: isSaving ? _jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "w-4 h-4 animate-spin" }), " Saving..."] }) :
234
+ showSuccess ? _jsxs(_Fragment, { children: [_jsx(Settings2, { className: "w-4 h-4" }), " Saved!"] }) :
235
+ _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 ? 'bg-primary text-white' : '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 ? 'bg-primary text-white' : '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: (() => {
236
+ const currentSocials = settings.localizedSocials?.[activeTab] || [];
237
+ return currentSocials.length > 0 ? (currentSocials.map((social) => {
238
+ const platform = AVAILABLE_PLATFORMS.find(p => p.name === social.platform);
239
+ 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 transition-colors", children: "Remove" })] }, social.id));
240
+ })) : (_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."] }));
241
+ })() })] })] }), _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) => {
242
+ const dateValue = e.target.value;
243
+ const currentTime = settings.launch_date?.includes('T') ? settings.launch_date.split('T')[1] : '00:00';
244
+ setSettings(prev => ({ ...prev, launch_date: dateValue ? `${dateValue}T${currentTime}` : '' }));
245
+ }, className: "w-full px-4 py-2 bg-dashboard-card border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-bold text-dashboard-text block", children: "Time (24-hour format)" }), _jsx("input", { type: "time", step: "60", value: settings.launch_date?.includes('T') ? settings.launch_date.split('T')[1] : '00:00', onChange: (e) => {
246
+ const timeValue = e.target.value;
247
+ const currentDate = settings.launch_date?.includes('T') ? settings.launch_date.split('T')[0] : new Date().toISOString().split('T')[0];
248
+ setSettings(prev => ({ ...prev, launch_date: timeValue ? `${currentDate}T${timeValue}` : '' }));
249
+ }, className: "w-full px-4 py-2 bg-dashboard-card border border-dashboard-border rounded-xl outline-none focus:ring-2 focus:ring-primary text-dashboard-text" })] }), _jsx("p", { className: "text-[10px] text-dashboard-text-secondary", children: "Used for countdown timers." })] })] }), _jsx(DomainLanguagesCard, { config: settings.domainLocaleConfig || [], onEdit: openDomainModal })] })] })] }), _jsx(DomainLanguagesModal, { isOpen: showDomainModal, config: settings.domainLocaleConfig || [], onSave: saveDomainConfig, onClose: closeDomainModal })] }));
219
250
  }
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.14",
4
4
  "description": "Website management and configuration plugin for the JHITS ecosystem",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,10 +25,10 @@
25
25
  }
26
26
  },
27
27
  "dependencies": {
28
- "lucide-react": "^0.564.0",
28
+ "lucide-react": "^0.577.0",
29
29
  "mongodb": "^7.1.0",
30
30
  "next-auth": "^4.24.13",
31
- "react-icons": "^5.5.0",
31
+ "react-icons": "^5.6.0",
32
32
  "@jhits/plugin-core": "0.0.10"
33
33
  },
34
34
  "peerDependencies": {
@@ -37,7 +37,7 @@
37
37
  "react-dom": ">=18.0.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@types/node": "^25.2.3",
40
+ "@types/node": "^25.3.3",
41
41
  "@types/react": "^19.2.14",
42
42
  "@types/react-dom": "^19.2.3",
43
43
  "next": "16.1.6",
@@ -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,25 @@
2
2
  * Website Settings Types
3
3
  */
4
4
 
5
+ export type SupportedLocale = 'en' | 'sv' | 'nl';
6
+
7
+ export interface DomainLocaleConfig {
8
+ domain: string;
9
+ locale: SupportedLocale;
10
+ allowUserOverride?: boolean;
11
+ }
12
+
13
+ export interface LocalizedContactInfo {
14
+ physicalAddress?: string;
15
+ phoneNumber?: string;
16
+ }
17
+
18
+ export interface LocalizedSocialLink {
19
+ id: number;
20
+ platform: string;
21
+ url: string;
22
+ }
23
+
5
24
  export interface WebsiteSettings {
6
25
  identifier: string;
7
26
  siteName?: string;
@@ -15,6 +34,9 @@ export interface WebsiteSettings {
15
34
  maintenanceMode?: boolean;
16
35
  launch_date?: string;
17
36
  socials?: SocialLink[];
37
+ localizedContactInfo?: Partial<Record<SupportedLocale, LocalizedContactInfo>>;
38
+ localizedSocials?: Partial<Record<SupportedLocale, LocalizedSocialLink[]>>;
39
+ domainLocaleConfig?: DomainLocaleConfig[];
18
40
  updatedAt?: Date;
19
41
  createdAt?: Date;
20
42
  }