@schandlergarcia/sf-web-components 1.2.16 → 1.2.17
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.
- package/package.json +1 -1
- package/scripts/reset-command-center.sh +121 -167
package/package.json
CHANGED
|
@@ -122,14 +122,67 @@ HOME="src/pages/Home.tsx"
|
|
|
122
122
|
echo "→ Updating ${HOME}..."
|
|
123
123
|
|
|
124
124
|
cat > "$HOME" << 'HOME_EOF'
|
|
125
|
-
import
|
|
125
|
+
import { useState } from "react";
|
|
126
|
+
import { useNavigate } from "react-router";
|
|
127
|
+
import UIInput from '@/components/library/ui/UIInput';
|
|
128
|
+
import UIButton from '@/components/library/ui/UIButton';
|
|
129
|
+
import { Search } from "lucide-react";
|
|
130
|
+
|
|
131
|
+
export default function HomePage() {
|
|
132
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
133
|
+
const navigate = useNavigate();
|
|
134
|
+
|
|
135
|
+
const handleSearch = () => {
|
|
136
|
+
const trimmed = searchQuery.trim();
|
|
137
|
+
if (trimmed) {
|
|
138
|
+
navigate(`/accounts?search=${encodeURIComponent(trimmed)}`);
|
|
139
|
+
} else {
|
|
140
|
+
navigate('/accounts');
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
145
|
+
if (e.key === "Enter") {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
handleSearch();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
126
150
|
|
|
127
|
-
|
|
128
|
-
|
|
151
|
+
return (
|
|
152
|
+
<div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8 bg-slate-50 dark:bg-slate-950 transition-colors">
|
|
153
|
+
<div className="w-full max-w-4xl">
|
|
154
|
+
<div className="text-center mb-8">
|
|
155
|
+
<h1 className="text-4xl font-bold text-slate-900 dark:text-slate-50 mb-4">Search</h1>
|
|
156
|
+
<p className="text-lg text-slate-600 dark:text-slate-300">Find records across your organization.</p>
|
|
157
|
+
</div>
|
|
158
|
+
<div className="flex flex-col gap-4">
|
|
159
|
+
<div className="relative">
|
|
160
|
+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
|
|
161
|
+
<UIInput
|
|
162
|
+
type="text"
|
|
163
|
+
value={searchQuery}
|
|
164
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
165
|
+
onKeyDown={handleKeyDown}
|
|
166
|
+
placeholder="Search..."
|
|
167
|
+
className="pl-10 w-full"
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
<div className="flex gap-3 justify-center">
|
|
171
|
+
<UIButton onClick={handleSearch} variant="primary">
|
|
172
|
+
Search
|
|
173
|
+
</UIButton>
|
|
174
|
+
<UIButton onClick={() => navigate('/accounts')} variant="secondary">
|
|
175
|
+
Browse All
|
|
176
|
+
</UIButton>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
129
182
|
}
|
|
130
183
|
HOME_EOF
|
|
131
184
|
|
|
132
|
-
echo " ✓ Home renders
|
|
185
|
+
echo " ✓ Home renders search interface"
|
|
133
186
|
echo ""
|
|
134
187
|
|
|
135
188
|
# ── 5. Ensure Search.tsx page exists ─────────────────────────────────────────
|
|
@@ -138,17 +191,60 @@ SEARCH="src/pages/Search.tsx"
|
|
|
138
191
|
echo "→ Updating ${SEARCH}..."
|
|
139
192
|
|
|
140
193
|
cat > "$SEARCH" << 'SEARCH_EOF'
|
|
141
|
-
import {
|
|
194
|
+
import { useState } from "react";
|
|
195
|
+
import { useNavigate } from "react-router";
|
|
196
|
+
import UIInput from '@/components/library/ui/UIInput';
|
|
197
|
+
import UIButton from '@/components/library/ui/UIButton';
|
|
198
|
+
import { Search as SearchIcon } from "lucide-react";
|
|
142
199
|
|
|
143
200
|
export default function Search() {
|
|
201
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
202
|
+
const navigate = useNavigate();
|
|
203
|
+
|
|
204
|
+
const handleSearch = () => {
|
|
205
|
+
const trimmed = searchQuery.trim();
|
|
206
|
+
if (trimmed) {
|
|
207
|
+
navigate(`/accounts?search=${encodeURIComponent(trimmed)}`);
|
|
208
|
+
} else {
|
|
209
|
+
navigate('/accounts');
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
214
|
+
if (e.key === "Enter") {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
handleSearch();
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
144
220
|
return (
|
|
145
|
-
<div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8">
|
|
221
|
+
<div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8 bg-slate-50 dark:bg-slate-950 transition-colors">
|
|
146
222
|
<div className="w-full max-w-4xl">
|
|
147
223
|
<div className="text-center mb-8">
|
|
148
224
|
<h1 className="text-4xl font-bold text-slate-900 dark:text-slate-50 mb-4">Search</h1>
|
|
149
225
|
<p className="text-lg text-slate-600 dark:text-slate-300">Find records across your organization.</p>
|
|
150
226
|
</div>
|
|
151
|
-
<
|
|
227
|
+
<div className="flex flex-col gap-4">
|
|
228
|
+
<div className="relative">
|
|
229
|
+
<SearchIcon className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
|
|
230
|
+
<UIInput
|
|
231
|
+
type="text"
|
|
232
|
+
value={searchQuery}
|
|
233
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
234
|
+
onKeyDown={handleKeyDown}
|
|
235
|
+
placeholder="Search..."
|
|
236
|
+
className="pl-10 w-full"
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
239
|
+
<div className="flex gap-3 justify-center">
|
|
240
|
+
<UIButton onClick={handleSearch} variant="primary">
|
|
241
|
+
Search
|
|
242
|
+
</UIButton>
|
|
243
|
+
<UIButton onClick={() => navigate('/accounts')} variant="secondary">
|
|
244
|
+
Browse All
|
|
245
|
+
</UIButton>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
152
248
|
</div>
|
|
153
249
|
</div>
|
|
154
250
|
);
|
|
@@ -165,178 +261,33 @@ echo "→ Updating ${ROUTES}..."
|
|
|
165
261
|
|
|
166
262
|
cat > "$ROUTES" << 'ROUTES_EOF'
|
|
167
263
|
import type { RouteObject } from 'react-router';
|
|
168
|
-
import
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const Home = lazy(() => import('./pages/Home'));
|
|
172
|
-
const Search = lazy(() => import('./pages/Search'));
|
|
173
|
-
const NotFound = lazy(() => import('./pages/NotFound'));
|
|
174
|
-
const TestAccPage = lazy(() => import("./pages/TestAccPage"));
|
|
175
|
-
const GlobalSearch = lazy(() => import("./features/global-search/pages/GlobalSearch"));
|
|
176
|
-
const DetailPage = lazy(() => import("./features/global-search/pages/DetailPage"));
|
|
177
|
-
|
|
178
|
-
function SuspenseWrap({ children }: { children: React.ReactNode }) {
|
|
179
|
-
return <Suspense fallback={<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">Loading...</div>}>{children}</Suspense>;
|
|
180
|
-
}
|
|
264
|
+
import Home from './pages/Home';
|
|
265
|
+
import NotFound from './pages/NotFound';
|
|
266
|
+
import AuthAppLayout from "./features/authentication/layouts/AuthAppLayout";
|
|
181
267
|
|
|
182
268
|
export const routes: RouteObject[] = [
|
|
183
269
|
{
|
|
184
270
|
path: "/",
|
|
185
|
-
element:
|
|
186
|
-
<SuspenseWrap>
|
|
187
|
-
<AppLayout />
|
|
188
|
-
</SuspenseWrap>
|
|
189
|
-
),
|
|
271
|
+
element: <AuthAppLayout />,
|
|
190
272
|
children: [
|
|
191
273
|
{
|
|
192
274
|
index: true,
|
|
193
|
-
element: <
|
|
194
|
-
handle: { showInNavigation: true,
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
path: "search",
|
|
198
|
-
element: <SuspenseWrap><Search /></SuspenseWrap>,
|
|
199
|
-
handle: { showInNavigation: true, showNavBar: true, label: 'Search' }
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
path: "test-acc",
|
|
203
|
-
element: <SuspenseWrap><TestAccPage /></SuspenseWrap>,
|
|
204
|
-
handle: { showInNavigation: true, label: "Test ACC" }
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
path: "global-search/:query",
|
|
208
|
-
element: (
|
|
209
|
-
<SuspenseWrap>
|
|
210
|
-
<GlobalSearch />
|
|
211
|
-
</SuspenseWrap>
|
|
212
|
-
),
|
|
213
|
-
handle: { showInNavigation: false }
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
path: "object/:objectApiName/:recordId",
|
|
217
|
-
element: (
|
|
218
|
-
<SuspenseWrap>
|
|
219
|
-
<DetailPage />
|
|
220
|
-
</SuspenseWrap>
|
|
221
|
-
),
|
|
222
|
-
handle: { showInNavigation: false }
|
|
275
|
+
element: <Home />,
|
|
276
|
+
handle: { showInNavigation: true, label: "Home" }
|
|
223
277
|
},
|
|
224
278
|
{
|
|
225
279
|
path: '*',
|
|
226
|
-
element: <
|
|
227
|
-
}
|
|
280
|
+
element: <NotFound />
|
|
281
|
+
}
|
|
228
282
|
]
|
|
229
283
|
}
|
|
230
284
|
];
|
|
231
285
|
ROUTES_EOF
|
|
232
286
|
|
|
233
|
-
echo " ✓ Routes updated (Home at
|
|
234
|
-
echo ""
|
|
235
|
-
|
|
236
|
-
# ── 7. Reset appLayout.tsx (nav on Home/Search only) ─────────────────────────
|
|
237
|
-
|
|
238
|
-
LAYOUT="src/appLayout.tsx"
|
|
239
|
-
echo "→ Updating ${LAYOUT}..."
|
|
240
|
-
|
|
241
|
-
cat > "$LAYOUT" << 'LAYOUT_EOF'
|
|
242
|
-
import { AgentforceConversationClient } from "./components/AgentforceConversationClient";
|
|
243
|
-
import { Outlet, Link, useLocation, useMatches } from "react-router";
|
|
244
|
-
import { getAllRoutes } from "./router-utils";
|
|
245
|
-
import { useState } from "react";
|
|
246
|
-
|
|
247
|
-
export default function AppLayout() {
|
|
248
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
249
|
-
const location = useLocation();
|
|
250
|
-
const matches = useMatches();
|
|
251
|
-
|
|
252
|
-
const showNavBar = matches.some(
|
|
253
|
-
(m) => (m.handle as Record<string, unknown>)?.showNavBar === true,
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
const isActive = (path: string) => location.pathname === path;
|
|
257
|
-
|
|
258
|
-
const toggleMenu = () => setIsOpen(!isOpen);
|
|
259
|
-
|
|
260
|
-
const navigationRoutes: { path: string; label: string }[] = getAllRoutes()
|
|
261
|
-
.filter(
|
|
262
|
-
(route) =>
|
|
263
|
-
route.handle?.showInNavigation === true &&
|
|
264
|
-
route.fullPath !== undefined &&
|
|
265
|
-
route.handle?.label !== undefined,
|
|
266
|
-
)
|
|
267
|
-
.map(
|
|
268
|
-
(route) =>
|
|
269
|
-
({
|
|
270
|
-
path: route.fullPath,
|
|
271
|
-
label: route.handle?.label,
|
|
272
|
-
}) as { path: string; label: string },
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
return (
|
|
276
|
-
<>
|
|
277
|
-
{showNavBar && (
|
|
278
|
-
<nav className="bg-white border-b border-gray-200">
|
|
279
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
280
|
-
<div className="flex justify-between items-center h-16">
|
|
281
|
-
<Link to="/" className="text-xl font-semibold text-gray-900">
|
|
282
|
-
React App
|
|
283
|
-
</Link>
|
|
284
|
-
<button
|
|
285
|
-
onClick={toggleMenu}
|
|
286
|
-
className="p-2 rounded-md text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
287
|
-
aria-label="Toggle menu"
|
|
288
|
-
>
|
|
289
|
-
<div className="w-6 h-6 flex flex-col justify-center space-y-1.5">
|
|
290
|
-
<span
|
|
291
|
-
className={`block h-0.5 w-6 bg-current transition-all ${
|
|
292
|
-
isOpen ? "rotate-45 translate-y-2" : ""
|
|
293
|
-
}`}
|
|
294
|
-
/>
|
|
295
|
-
<span
|
|
296
|
-
className={`block h-0.5 w-6 bg-current transition-all ${isOpen ? "opacity-0" : ""}`}
|
|
297
|
-
/>
|
|
298
|
-
<span
|
|
299
|
-
className={`block h-0.5 w-6 bg-current transition-all ${
|
|
300
|
-
isOpen ? "-rotate-45 -translate-y-2" : ""
|
|
301
|
-
}`}
|
|
302
|
-
/>
|
|
303
|
-
</div>
|
|
304
|
-
</button>
|
|
305
|
-
</div>
|
|
306
|
-
{isOpen && (
|
|
307
|
-
<div className="pb-4">
|
|
308
|
-
<div className="flex flex-col space-y-2">
|
|
309
|
-
{navigationRoutes.map((item) => (
|
|
310
|
-
<Link
|
|
311
|
-
key={item.path}
|
|
312
|
-
to={item.path}
|
|
313
|
-
onClick={() => setIsOpen(false)}
|
|
314
|
-
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
315
|
-
isActive(item.path)
|
|
316
|
-
? "bg-blue-100 text-blue-700"
|
|
317
|
-
: "text-gray-700 hover:bg-gray-100"
|
|
318
|
-
}`}
|
|
319
|
-
>
|
|
320
|
-
{item.label}
|
|
321
|
-
</Link>
|
|
322
|
-
))}
|
|
323
|
-
</div>
|
|
324
|
-
</div>
|
|
325
|
-
)}
|
|
326
|
-
</div>
|
|
327
|
-
</nav>
|
|
328
|
-
)}
|
|
329
|
-
<Outlet />
|
|
330
|
-
<AgentforceConversationClient />
|
|
331
|
-
</>
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
LAYOUT_EOF
|
|
335
|
-
|
|
336
|
-
echo " ✓ Layout updated (nav bar on Home/Search pages)"
|
|
287
|
+
echo " ✓ Routes updated (Home at /)"
|
|
337
288
|
echo ""
|
|
338
289
|
|
|
339
|
-
# ──
|
|
290
|
+
# ── 7. Clear Vite cache ─────────────────────────────────────────────────────
|
|
340
291
|
|
|
341
292
|
echo "→ Cleaning caches…"
|
|
342
293
|
rm -rf node_modules/.vite 2>/dev/null && echo " ✓ Cleared Vite cache" || true
|
|
@@ -351,16 +302,19 @@ echo "║ Everything preserved: ║"
|
|
|
351
302
|
echo "║ • Theme (global.css + initialMode) ║"
|
|
352
303
|
echo "║ • Component library (cards, charts, etc.) ║"
|
|
353
304
|
echo "║ • HeroUI wrappers & theme providers ║"
|
|
354
|
-
echo "║ •
|
|
305
|
+
echo "║ • Authentication features ║"
|
|
355
306
|
echo "║ • All styles & dependencies ║"
|
|
356
307
|
echo "║ ║"
|
|
357
308
|
echo "║ Layout: ║"
|
|
358
|
-
echo "║ / → Home (
|
|
359
|
-
echo "║ /
|
|
360
|
-
echo "║
|
|
309
|
+
echo "║ / → Home (Search interface) ║"
|
|
310
|
+
echo "║ /accounts → Account search and browse ║"
|
|
311
|
+
echo "║ ║"
|
|
312
|
+
echo "║ Search functionality: ║"
|
|
313
|
+
echo "║ • Search button navigates to /accounts ║"
|
|
314
|
+
echo "║ • Enter key in search input triggers search║"
|
|
315
|
+
echo "║ • Browse All button shows all accounts ║"
|
|
361
316
|
echo "║ ║"
|
|
362
317
|
echo "║ Start building: ║"
|
|
363
|
-
echo "║ Edit src/components/pages/BlankDashboard.jsx║"
|
|
364
318
|
echo "║ npm run dev ║"
|
|
365
319
|
echo "╚════════════════════════════════════════════════╝"
|
|
366
320
|
echo ""
|