EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
page.tsx
Go to the documentation of this file.
1'use client';
2
3import { useState, useEffect } from 'react';
4import Link from 'next/link';
5
6interface UiOption {
7 id: number;
8 name: string;
9}
10
11interface Settings {
12 storeServerMesh: { [profile: string]: boolean };
13 initialUi: { [profile: string]: string };
14 directMesh: boolean;
15 defaultUi: string;
16 commandsForLane: string;
17 installCommands: string;
18}
19
20export default function StoreConfigurationPage() {
21 const [uiOptions, setUiOptions] = useState<UiOption[]>([]);
22 const [settings, setSettings] = useState<Settings>({
23 storeServerMesh: {},
24 initialUi: {},
25 directMesh: false,
26 defaultUi: '',
27 commandsForLane: '',
28 installCommands: ''
29 });
30 const [loading, setLoading] = useState(true);
31
32 const profiles = ['0', '1', '2', '3', '4', '5', '6', '7', '8'];
33
34 useEffect(() => {
35 loadData();
36 }, []);
37
38 const loadData = async () => {
39 try {
40 setLoading(true);
41 // Load UI options
42 // In production, this would call: /api/v1/elink/ui-list
43 // For now, using placeholder data
44 setUiOptions([
45 { id: 1, name: 'Default POS Interface' },
46 { id: 2, name: 'Touch Screen UI' },
47 { id: 3, name: 'Mobile UI' },
48 { id: 4, name: 'Quick Service UI' },
49 { id: 5, name: 'Restaurant UI' }
50 ]);
51
52 // Load current settings
53 // In production, this would call: /api/v1/elink/lane-settings
54 const defaultSettings: Settings = {
55 storeServerMesh: {},
56 initialUi: {},
57 directMesh: true,
58 defaultUi: '1',
59 commandsForLane: '',
60 installCommands: ''
61 };
62
63 profiles.forEach(p => {
64 defaultSettings.storeServerMesh[p] = true;
65 defaultSettings.initialUi[p] = '';
66 });
67
68 setSettings(defaultSettings);
69 } catch (error) {
70 console.error('Error loading configuration:', error);
71 alert('Failed to load configuration data');
72 } finally {
73 setLoading(false);
74 }
75 };
76
77 const handleToggleChange = (profile: string, value: boolean) => {
78 setSettings(prev => ({
79 ...prev,
80 storeServerMesh: {
81 ...prev.storeServerMesh,
82 [profile]: value
83 }
84 }));
85 saveSetting('StoreServerAllowMesh', profile, value);
86 };
87
88 const handleUiChange = (profile: string, value: string) => {
89 setSettings(prev => ({
90 ...prev,
91 initialUi: {
92 ...prev.initialUi,
93 [profile]: value
94 }
95 }));
96 saveSetting('LaneCoden400.UserInterfaceN', profile, value);
97 };
98
99 const handleDirectMeshChange = (value: boolean) => {
100 setSettings(prev => ({ ...prev, directMesh: value }));
101 saveSetting('LaneInstallDirectMesh', '0', value);
102 };
103
104 const handleDefaultUiChange = (value: string) => {
105 setSettings(prev => ({ ...prev, defaultUi: value }));
106 saveSetting('LaneCoden400.UserInterfaceN', '0', value);
107 };
108
109 const handleCommandsChange = (value: string) => {
110 setSettings(prev => ({ ...prev, commandsForLane: value }));
111 };
112
113 const handleInstallCommandsChange = (value: string) => {
114 setSettings(prev => ({ ...prev, installCommands: value }));
115 };
116
117 const saveSetting = async (settingName: string, profile: string, value: any) => {
118 try {
119 // In production, this would call: /api/v1/elink/lane-settings
120 // POST with { settingName, profile, value }
121 console.log('Saving:', settingName, profile, value);
122
123 // Placeholder - in production would be actual API call
124 // await apiClient.saveLaneSetting(settingName, profile, value);
125 } catch (error) {
126 console.error('Error saving setting:', error);
127 alert('Failed to save setting');
128 }
129 };
130
131 const saveTextAreaSetting = async (settingName: string) => {
132 const value = settingName === 'LaneCoden400.FposAllCtl'
133 ? settings.commandsForLane
134 : settings.installCommands;
135
136 await saveSetting(settingName, '0', value);
137 alert('Commands saved successfully');
138 };
139
140 if (loading) {
141 return (
142 <div className="p-8">
143 <div className="text-center">Loading configuration...</div>
144 </div>
145 );
146 }
147
148 return (
149 <div className="min-h-screen bg-bg">
150 {/* Top Bar */}
151 <div className="bg-[#00946b] text-white p-4 shadow-lg">
152 <div className="flex items-center">
153 <img
154 src="/logo/fieldpine-logo.png"
155 alt="Fieldpine Logo"
156 className="w-48 h-auto rounded-lg shadow-lg mr-6"
157 onError={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }}
158 />
159 <div className="text-sm">
160 [ <Link href="/pages/home" className="hover:underline">Home</Link> ]
161 {' '}[ <Link href="/pages/settings/stores" className="hover:underline">Stores</Link>
162 {' '}<span className="text-xl">→</span> ] Configure Lane Definition
163 </div>
164 </div>
165 </div>
166
167 {/* Page Title */}
168 <div className="bg-surface border-b-2 border-[#00543b] p-4">
169 <h1 className="text-3xl font-bold text-text">Configure Lane Definitions</h1>
170 </div>
171
172 <div className="p-6">
173 {/* Profile Settings Table */}
174 <div className="bg-surface rounded-lg shadow-md overflow-x-auto mt-8">
175 <table className="w-full border-collapse">
176 <thead>
177 <tr className="bg-[#00543b] text-white">
178 <th className="p-3 text-left border border-border">Setting</th>
179 {profiles.map(p => (
180 <th key={p} className="p-3 text-center border border-border">
181 {p === '0' ? 'No Profile' : `Profile ${p}`}
182 </th>
183 ))}
184 <th className="p-3 text-center border border-border">Version</th>
185 </tr>
186 </thead>
187 <tbody>
188 {/* Store Server as Database */}
189 <tr className="hover:bg-surface-2">
190 <td className="p-3 border border-border font-semibold">
191 Store Server as Database
192 </td>
193 {profiles.map(p => (
194 <td key={p} className="p-3 border border-border text-center">
195 <label className="relative inline-flex items-center cursor-pointer">
196 <input
197 type="checkbox"
198 className="sr-only peer"
199 checked={settings.storeServerMesh[p] || false}
200 onChange={(e) => handleToggleChange(p, e.target.checked)}
201 />
202 <div className="w-11 h-6 bg-surface-2 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#00543b]/30 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-surface after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#00543b]"></div>
203 </label>
204 </td>
205 ))}
206 <td className="p-3 border border-border text-center text-sm text-muted">
207 RL.174
208 </td>
209 </tr>
210 <tr>
211 <td colSpan={11} className="p-2 bg-surface-2 text-sm text-muted border border-border">
212 Can a store server act as the primary database for lanes within the store. This is generally enabled.
213 </td>
214 </tr>
215
216 {/* Initial User Interface on Install */}
217 <tr className="hover:bg-surface-2">
218 <td className="p-3 border border-border font-semibold">
219 Initial User Interface on Install
220 </td>
221 {profiles.map(p => (
222 <td key={p} className="p-3 border border-border">
223 <select
224 className="w-full px-2 py-1 border border-border rounded focus:ring-2 focus:ring-[#00543b] focus:border-[#00543b]"
225 value={settings.initialUi[p] || ''}
226 onChange={(e) => handleUiChange(p, e.target.value)}
227 >
228 <option value="">--System default</option>
229 {uiOptions.map(ui => (
230 <option key={ui.id} value={ui.id}>{ui.name}</option>
231 ))}
232 </select>
233 </td>
234 ))}
235 <td className="p-3 border border-border text-center text-sm text-muted">
236 RL.174
237 </td>
238 </tr>
239 <tr>
240 <td colSpan={11} className="p-2 bg-surface-2 text-sm text-muted border border-border">
241 When a new lane is installed, which User Interface should it initially be assigned
242 </td>
243 </tr>
244 </tbody>
245 </table>
246 </div>
247
248 {/* Fieldpine.com Lanes Configuration */}
249 <div className="bg-surface rounded-lg shadow-md p-6 mt-8">
250 <h2 className="text-2xl font-bold text-text mb-6">
251 Configuration for Fieldpine.com Lanes
252 </h2>
253
254 {/* Direct Mesh Communication */}
255 <div className="flex items-start gap-4 mb-6 pb-6 border-b border-border">
256 <label className="relative inline-flex items-center cursor-pointer mt-1">
257 <input
258 type="checkbox"
259 className="sr-only peer"
260 checked={settings.directMesh}
261 onChange={(e) => handleDirectMeshChange(e.target.checked)}
262 />
263 <div className="w-14 h-7 bg-surface-2 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#00543b]/30 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-surface after:border-border after:border after:rounded-full after:h-6 after:w-6 after:transition-all peer-checked:bg-[#00543b]"></div>
264 </label>
265 <div>
266 <h3 className="font-semibold text-lg text-text">
267 Allow PosGreen lanes to communicate directly to Fieldpine.com
268 </h3>
269 <p className="text-muted text-sm mt-1">
270 Lanes that do this are charged on a usage volume basis
271 </p>
272 </div>
273 </div>
274
275 {/* User Interface Selection */}
276 <div className="mb-6">
277 <h3 className="font-semibold text-text mb-2">User Interface</h3>
278 <select
279 className="w-full max-w-md px-3 py-2 border border-border rounded-lg focus:ring-2 focus:ring-[#00543b] focus:border-[#00543b]"
280 value={settings.defaultUi}
281 onChange={(e) => handleDefaultUiChange(e.target.value)}
282 >
283 <option value="">--System default</option>
284 {uiOptions.map(ui => (
285 <option key={ui.id} value={ui.id}>{ui.name}</option>
286 ))}
287 </select>
288 <p className="text-muted text-sm mt-2">
289 The User Interface (aka "UI" or "skin") controls both how the screen the Pos displays and operates.
290 </p>
291 </div>
292
293 {/* Commands for Each Lane */}
294 <div className="mb-6">
295 <h3 className="font-semibold text-text mb-2">Commands for each lane</h3>
296 <textarea
297 rows={10}
298 className="w-full px-3 py-2 border border-border rounded-lg focus:ring-2 focus:ring-[#00543b] focus:border-[#00543b] font-mono text-sm"
299 placeholder="Configuration Commands for each lane"
300 value={settings.commandsForLane}
301 onChange={(e) => handleCommandsChange(e.target.value)}
302 onBlur={() => saveTextAreaSetting('LaneCoden400.FposAllCtl')}
303 />
304 </div>
305
306 {/* Install Commands for Each Lane */}
307 <div className="mb-6">
308 <h3 className="font-semibold text-text mb-2">Install Commands for each lane</h3>
309 <p className="text-muted text-sm mb-2">
310 These commands are deployed to the lane on initial install only.
311 </p>
312 <textarea
313 rows={10}
314 className="w-full px-3 py-2 border border-border rounded-lg focus:ring-2 focus:ring-[#00543b] focus:border-[#00543b] font-mono text-sm"
315 placeholder="Configuration Commands for each lane"
316 value={settings.installCommands}
317 onChange={(e) => handleInstallCommandsChange(e.target.value)}
318 onBlur={() => saveTextAreaSetting('LaneCoden400.FposBlankCtl')}
319 />
320 </div>
321 </div>
322
323 {/* Back Button */}
324 <div className="mt-6">
325 <Link
326 href="/pages/settings/stores"
327 className="inline-flex items-center px-6 py-3 bg-muted text-white rounded-lg hover:bg-muted/90 transition-colors"
328 >
329 ← Back to Stores
330 </Link>
331 </div>
332 </div>
333 </div>
334 );
335}