@snapdragonsnursery/react-components 1.1.0 → 1.1.1
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/README.md +113 -474
- package/package.json +1 -1
- package/src/ChildSearchModal.jsx +4 -1
package/README.md
CHANGED
|
@@ -1,528 +1,167 @@
|
|
|
1
|
-
# react-components
|
|
1
|
+
# @snapdragonsnursery/react-components
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A collection of reusable React components for Snapdragons Nursery applications.
|
|
4
4
|
|
|
5
5
|
## Components
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
7
|
+
- **ChildSearchModal**: Advanced child search and selection component with filtering, pagination, and multi-select capabilities
|
|
8
|
+
- **AuthButtons**: Authentication buttons for MSAL integration
|
|
9
|
+
- **ThemeToggle**: Dark/light theme toggle component
|
|
10
|
+
- **LandingPage**: Landing page component with authentication
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
```
|
|
14
|
+
```bash
|
|
17
15
|
npm install @snapdragonsnursery/react-components
|
|
18
16
|
```
|
|
19
17
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
Your project must have the following installed:
|
|
23
|
-
|
|
24
|
-
### Core Dependencies
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install react react-dom
|
|
28
|
-
npm install @azure/msal-browser @azure/msal-react
|
|
29
|
-
npm install @headlessui/react @heroicons/react
|
|
30
|
-
```
|
|
18
|
+
## Quick Start
|
|
31
19
|
|
|
32
|
-
|
|
20
|
+
```jsx
|
|
21
|
+
import { ChildSearchModal } from '@snapdragonsnursery/react-components';
|
|
33
22
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
function MyComponent() {
|
|
24
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<ChildSearchModal
|
|
28
|
+
isOpen={isModalOpen}
|
|
29
|
+
onClose={() => setIsModalOpen(false)}
|
|
30
|
+
onSelect={(child) => console.log('Selected:', child)}
|
|
31
|
+
title="Search for a Child"
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
37
35
|
```
|
|
38
36
|
|
|
39
|
-
##
|
|
37
|
+
## Environment Variables
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
# Core authentication dependencies
|
|
45
|
-
npm install @azure/msal-browser @azure/msal-react
|
|
39
|
+
Set these environment variables in your application:
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# Tailwind CSS (required for styling)
|
|
51
|
-
npm install -D tailwindcss postcss autoprefixer
|
|
52
|
-
npx tailwindcss init -p
|
|
53
|
-
|
|
54
|
-
# Install this component library
|
|
55
|
-
npm install @snapdragonsnursery/react-components
|
|
41
|
+
```env
|
|
42
|
+
VITE_COMMON_API_BASE_URL=https://snaps-common-api.azurewebsites.net
|
|
56
43
|
```
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Update `tailwind.config.js`:
|
|
45
|
+
## Documentation
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
|
66
|
-
darkMode: "class",
|
|
67
|
-
theme: {
|
|
68
|
-
extend: {},
|
|
69
|
-
},
|
|
70
|
-
plugins: [],
|
|
71
|
-
};
|
|
72
|
-
```
|
|
47
|
+
- [ChildSearchModal Documentation](./CHILD_SEARCH_MODAL_DOCUMENTATION.md)
|
|
48
|
+
- [ChildSearchModal README](./CHILD_SEARCH_README.md)
|
|
49
|
+
- [Release Guide](./RELEASE.md)
|
|
73
50
|
|
|
74
|
-
|
|
51
|
+
---
|
|
75
52
|
|
|
76
|
-
|
|
77
|
-
@tailwind base;
|
|
78
|
-
@tailwind components;
|
|
79
|
-
@tailwind utilities;
|
|
53
|
+
## 🚀 Publishing New Versions
|
|
80
54
|
|
|
81
|
-
|
|
82
|
-
body {
|
|
83
|
-
margin: 0;
|
|
84
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
|
85
|
-
"Oxygen", "Ubuntu", "Cantarell", "Open Sans", "Helvetica Neue", sans-serif;
|
|
86
|
-
-webkit-font-smoothing: antialiased;
|
|
87
|
-
-moz-osx-font-smoothing: grayscale;
|
|
88
|
-
}
|
|
55
|
+
### Quick Release (Recommended)
|
|
89
56
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```
|
|
57
|
+
```bash
|
|
58
|
+
# Patch release (bug fixes) - 1.1.0 → 1.1.1
|
|
59
|
+
npm run release
|
|
94
60
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
Create `src/utils/authConfig.js`:
|
|
98
|
-
|
|
99
|
-
```javascript
|
|
100
|
-
import { LogLevel } from "@azure/msal-browser";
|
|
101
|
-
|
|
102
|
-
export const msalConfig = {
|
|
103
|
-
auth: {
|
|
104
|
-
clientId: "2e2d9456-a0b7-4651-a8f8-c979ed1486b0", // Snapdragons Azure AD App
|
|
105
|
-
authority:
|
|
106
|
-
"https://login.microsoftonline.com/d098ee48-9874-4959-8229-da24c99c36fb",
|
|
107
|
-
redirectUri: window.location.origin,
|
|
108
|
-
postLogoutRedirectUri: window.location.origin,
|
|
109
|
-
navigateToLoginRequestUrl: false,
|
|
110
|
-
},
|
|
111
|
-
cache: {
|
|
112
|
-
cacheLocation: "sessionStorage",
|
|
113
|
-
storeAuthStateInCookie: false,
|
|
114
|
-
},
|
|
115
|
-
system: {
|
|
116
|
-
loggerOptions: {
|
|
117
|
-
loggerCallback: (level, message, containsPii) => {
|
|
118
|
-
if (containsPii) return;
|
|
119
|
-
switch (level) {
|
|
120
|
-
case LogLevel.Error:
|
|
121
|
-
console.error(message);
|
|
122
|
-
return;
|
|
123
|
-
case LogLevel.Warning:
|
|
124
|
-
console.warn(message);
|
|
125
|
-
return;
|
|
126
|
-
default:
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
logLevel: LogLevel.Warning,
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export const loginRequest = {
|
|
136
|
-
scopes: ["User.Read", "email", "profile", "Directory.Read.All"],
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
export const adminConfig = {
|
|
140
|
-
adminEmailDomains: [],
|
|
141
|
-
adminEmails: [
|
|
142
|
-
"james@snapdragonsnursery.com",
|
|
143
|
-
"accounts@snapdragonsnursery.com",
|
|
144
|
-
],
|
|
145
|
-
adminGroupIds: [],
|
|
146
|
-
adminRoles: ["FundingAdmin", "Admin"],
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
export const isUserAdmin = (account, idTokenClaims = null) => {
|
|
150
|
-
if (!account) return false;
|
|
151
|
-
const claims = idTokenClaims || account.idTokenClaims;
|
|
152
|
-
const email = account.username || claims?.email || claims?.preferred_username;
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
email &&
|
|
156
|
-
adminConfig.adminEmailDomains.some((domain) =>
|
|
157
|
-
email.toLowerCase().endsWith(`@${domain.toLowerCase()}`)
|
|
158
|
-
)
|
|
159
|
-
) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
email &&
|
|
165
|
-
adminConfig.adminEmails.some(
|
|
166
|
-
(adminEmail) => email.toLowerCase() === adminEmail.toLowerCase()
|
|
167
|
-
)
|
|
168
|
-
) {
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (claims?.groups && adminConfig.adminGroupIds.length > 0) {
|
|
173
|
-
const userGroups = Array.isArray(claims.groups)
|
|
174
|
-
? claims.groups
|
|
175
|
-
: [claims.groups];
|
|
176
|
-
if (
|
|
177
|
-
userGroups.some((groupId) => adminConfig.adminGroupIds.includes(groupId))
|
|
178
|
-
) {
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (claims?.roles && adminConfig.adminRoles.length > 0) {
|
|
184
|
-
const userRoles = Array.isArray(claims.roles)
|
|
185
|
-
? claims.roles
|
|
186
|
-
: [claims.roles];
|
|
187
|
-
if (userRoles.some((role) => adminConfig.adminRoles.includes(role))) {
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return false;
|
|
193
|
-
};
|
|
194
|
-
```
|
|
61
|
+
# Minor release (new features) - 1.1.0 → 1.2.0
|
|
62
|
+
npm run release:minor
|
|
195
63
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
Create `src/utils/AuthProvider.jsx`:
|
|
199
|
-
|
|
200
|
-
```javascript
|
|
201
|
-
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
202
|
-
import { useMsal, useAccount } from "@azure/msal-react";
|
|
203
|
-
import { isUserAdmin } from "./authConfig";
|
|
204
|
-
|
|
205
|
-
const AuthContext = createContext();
|
|
206
|
-
|
|
207
|
-
export const useAuth = () => {
|
|
208
|
-
const context = useContext(AuthContext);
|
|
209
|
-
if (!context) {
|
|
210
|
-
throw new Error("useAuth must be used within an AuthProvider");
|
|
211
|
-
}
|
|
212
|
-
return context;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
export const AuthProvider = ({ children }) => {
|
|
216
|
-
const { instance, accounts } = useMsal();
|
|
217
|
-
const account = useAccount(accounts[0] || {});
|
|
218
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
219
|
-
const [userRole, setUserRole] = useState(null);
|
|
220
|
-
|
|
221
|
-
useEffect(() => {
|
|
222
|
-
const checkUserRole = async () => {
|
|
223
|
-
if (account) {
|
|
224
|
-
const adminStatus = isUserAdmin(account);
|
|
225
|
-
setUserRole(adminStatus ? "admin" : "employee");
|
|
226
|
-
} else {
|
|
227
|
-
setUserRole(null);
|
|
228
|
-
}
|
|
229
|
-
setIsLoading(false);
|
|
230
|
-
};
|
|
231
|
-
checkUserRole();
|
|
232
|
-
}, [account]);
|
|
233
|
-
|
|
234
|
-
const login = async () => {
|
|
235
|
-
try {
|
|
236
|
-
await instance.loginPopup();
|
|
237
|
-
} catch (error) {
|
|
238
|
-
console.error("Login failed:", error);
|
|
239
|
-
throw error;
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
const logout = async () => {
|
|
244
|
-
try {
|
|
245
|
-
await instance.logoutPopup();
|
|
246
|
-
} catch (error) {
|
|
247
|
-
console.error("Logout failed:", error);
|
|
248
|
-
throw error;
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const isAuthenticated = !!account;
|
|
253
|
-
const isAdmin = userRole === "admin";
|
|
254
|
-
|
|
255
|
-
const value = {
|
|
256
|
-
account,
|
|
257
|
-
isAuthenticated,
|
|
258
|
-
isAdmin,
|
|
259
|
-
userRole,
|
|
260
|
-
isLoading,
|
|
261
|
-
login,
|
|
262
|
-
logout,
|
|
263
|
-
instance,
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
|
267
|
-
};
|
|
64
|
+
# Major release (breaking changes) - 1.1.0 → 2.0.0
|
|
65
|
+
npm run release:major
|
|
268
66
|
```
|
|
269
67
|
|
|
270
|
-
###
|
|
271
|
-
|
|
272
|
-
Create `src/utils/theme.jsx`:
|
|
273
|
-
|
|
274
|
-
```javascript
|
|
275
|
-
import { createContext, useContext, useEffect, useState } from "react";
|
|
276
|
-
|
|
277
|
-
const ThemeContext = createContext();
|
|
278
|
-
|
|
279
|
-
export function ThemeProvider({ children }) {
|
|
280
|
-
const [theme, setTheme] = useState("system");
|
|
281
|
-
|
|
282
|
-
useEffect(() => {
|
|
283
|
-
const savedTheme = localStorage.getItem("theme");
|
|
284
|
-
if (savedTheme && ["light", "dark", "system"].includes(savedTheme)) {
|
|
285
|
-
setTheme(savedTheme);
|
|
286
|
-
} else {
|
|
287
|
-
setTheme("system");
|
|
288
|
-
}
|
|
289
|
-
}, []);
|
|
290
|
-
|
|
291
|
-
useEffect(() => {
|
|
292
|
-
const applyTheme = () => {
|
|
293
|
-
if (theme === "system") {
|
|
294
|
-
const systemPrefersDark = window.matchMedia(
|
|
295
|
-
"(prefers-color-scheme: dark)"
|
|
296
|
-
).matches;
|
|
297
|
-
if (systemPrefersDark) {
|
|
298
|
-
document.documentElement.classList.add("dark");
|
|
299
|
-
} else {
|
|
300
|
-
document.documentElement.classList.remove("dark");
|
|
301
|
-
}
|
|
302
|
-
} else if (theme === "dark") {
|
|
303
|
-
document.documentElement.classList.add("dark");
|
|
304
|
-
} else {
|
|
305
|
-
document.documentElement.classList.remove("dark");
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
applyTheme();
|
|
310
|
-
localStorage.setItem("theme", theme);
|
|
311
|
-
}, [theme]);
|
|
312
|
-
|
|
313
|
-
useEffect(() => {
|
|
314
|
-
if (theme !== "system") return;
|
|
315
|
-
|
|
316
|
-
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
317
|
-
const handleChange = () => {
|
|
318
|
-
if (theme === "system") {
|
|
319
|
-
if (mediaQuery.matches) {
|
|
320
|
-
document.documentElement.classList.add("dark");
|
|
321
|
-
} else {
|
|
322
|
-
document.documentElement.classList.remove("dark");
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
mediaQuery.addEventListener("change", handleChange);
|
|
328
|
-
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
329
|
-
}, [theme]);
|
|
330
|
-
|
|
331
|
-
return (
|
|
332
|
-
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
333
|
-
{children}
|
|
334
|
-
</ThemeContext.Provider>
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export function useTheme() {
|
|
339
|
-
const context = useContext(ThemeContext);
|
|
340
|
-
if (context === undefined) {
|
|
341
|
-
throw new Error("useTheme must be used within a ThemeProvider");
|
|
342
|
-
}
|
|
343
|
-
return context;
|
|
344
|
-
}
|
|
345
|
-
```
|
|
68
|
+
### GitHub Actions (Web Interface)
|
|
346
69
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
import React from "react";
|
|
353
|
-
import ReactDOM from "react-dom/client";
|
|
354
|
-
import App from "./App.jsx";
|
|
355
|
-
import "./index.css";
|
|
356
|
-
import { MsalProvider } from "@azure/msal-react";
|
|
357
|
-
import { PublicClientApplication } from "@azure/msal-browser";
|
|
358
|
-
import { msalConfig } from "./utils/authConfig";
|
|
359
|
-
import { AuthProvider } from "./utils/AuthProvider";
|
|
360
|
-
import { ThemeProvider } from "./utils/theme";
|
|
361
|
-
|
|
362
|
-
const msalInstance = new PublicClientApplication(msalConfig);
|
|
363
|
-
|
|
364
|
-
ReactDOM.createRoot(document.getElementById("root")).render(
|
|
365
|
-
<React.StrictMode>
|
|
366
|
-
<MsalProvider instance={msalInstance}>
|
|
367
|
-
<AuthProvider>
|
|
368
|
-
<ThemeProvider>
|
|
369
|
-
<App />
|
|
370
|
-
</ThemeProvider>
|
|
371
|
-
</AuthProvider>
|
|
372
|
-
</MsalProvider>
|
|
373
|
-
</React.StrictMode>
|
|
374
|
-
);
|
|
375
|
-
```
|
|
70
|
+
1. Go to [GitHub Actions](https://github.com/Snapdragons-Nursery/react-components/actions)
|
|
71
|
+
2. Click "Publish Package"
|
|
72
|
+
3. Click "Run workflow"
|
|
73
|
+
4. Select version type (patch/minor/major)
|
|
74
|
+
5. Click "Run workflow"
|
|
376
75
|
|
|
377
|
-
###
|
|
378
|
-
|
|
379
|
-
Create `src/components/Navbar.jsx`:
|
|
380
|
-
|
|
381
|
-
```javascript
|
|
382
|
-
import React, { useState, useEffect } from "react";
|
|
383
|
-
import { AuthButtons } from "@snapdragonsnursery/react-components";
|
|
384
|
-
import { useAuth } from "../utils/AuthProvider";
|
|
385
|
-
import { useTheme } from "../utils/theme";
|
|
386
|
-
|
|
387
|
-
const Navbar = () => {
|
|
388
|
-
const { account, userRole, instance } = useAuth();
|
|
389
|
-
const { theme, setTheme } = useTheme();
|
|
390
|
-
const [authState, setAuthState] = useState({
|
|
391
|
-
isAuthenticated: !!account,
|
|
392
|
-
accountsCount: account ? 1 : 0,
|
|
393
|
-
account,
|
|
394
|
-
instance,
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
useEffect(() => {
|
|
398
|
-
setAuthState({
|
|
399
|
-
isAuthenticated: !!account,
|
|
400
|
-
accountsCount: account ? 1 : 0,
|
|
401
|
-
account,
|
|
402
|
-
instance,
|
|
403
|
-
});
|
|
404
|
-
}, [account, instance]);
|
|
76
|
+
### Manual Commands
|
|
405
77
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
</span>
|
|
412
|
-
</div>
|
|
413
|
-
<div className="flex items-center space-x-4">
|
|
414
|
-
<AuthButtons
|
|
415
|
-
theme={theme}
|
|
416
|
-
setTheme={setTheme}
|
|
417
|
-
authState={authState}
|
|
418
|
-
setAuthState={setAuthState}
|
|
419
|
-
/>
|
|
420
|
-
</div>
|
|
421
|
-
</nav>
|
|
422
|
-
);
|
|
423
|
-
};
|
|
78
|
+
```bash
|
|
79
|
+
# Just bump version
|
|
80
|
+
npm run version:patch
|
|
81
|
+
npm run version:minor
|
|
82
|
+
npm run version:major
|
|
424
83
|
|
|
425
|
-
|
|
84
|
+
# Bump and publish
|
|
85
|
+
npm run publish:patch
|
|
86
|
+
npm run publish:minor
|
|
87
|
+
npm run publish:major
|
|
426
88
|
```
|
|
427
89
|
|
|
428
|
-
###
|
|
429
|
-
|
|
430
|
-
Update `src/App.jsx`:
|
|
431
|
-
|
|
432
|
-
```javascript
|
|
433
|
-
import Navbar from "./components/Navbar";
|
|
90
|
+
### Pre-release Versions (Beta)
|
|
434
91
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
</>
|
|
441
|
-
);
|
|
442
|
-
}
|
|
92
|
+
```bash
|
|
93
|
+
# Create beta version
|
|
94
|
+
npm run publish:prepatch
|
|
95
|
+
npm run publish:preminor
|
|
96
|
+
npm run publish:premajor
|
|
443
97
|
|
|
444
|
-
|
|
98
|
+
# Install beta in consuming apps
|
|
99
|
+
npm install @snapdragonsnursery/react-components@beta
|
|
445
100
|
```
|
|
446
101
|
|
|
447
|
-
##
|
|
102
|
+
## Version Types
|
|
448
103
|
|
|
449
|
-
|
|
104
|
+
| Type | Example | Use Case |
|
|
105
|
+
|------|---------|----------|
|
|
106
|
+
| **patch** | 1.1.0 → 1.1.1 | Bug fixes, documentation |
|
|
107
|
+
| **minor** | 1.1.0 → 1.2.0 | New features, backward compatible |
|
|
108
|
+
| **major** | 1.1.0 → 2.0.0 | Breaking changes |
|
|
109
|
+
| **prepatch** | 1.1.0 → 1.1.1-0 | Beta patch release |
|
|
110
|
+
| **preminor** | 1.1.0 → 1.2.0-0 | Beta minor release |
|
|
111
|
+
| **premajor** | 1.1.0 → 2.0.0-0 | Beta major release |
|
|
450
112
|
|
|
451
|
-
|
|
452
|
-
- Show user profile picture or initials when authenticated
|
|
453
|
-
- Provide a dropdown menu with theme toggle and logout option
|
|
454
|
-
- Handle all authentication flows automatically
|
|
113
|
+
## Release Checklist
|
|
455
114
|
|
|
456
|
-
|
|
115
|
+
Before releasing:
|
|
457
116
|
|
|
458
|
-
|
|
117
|
+
- [ ] All changes committed and pushed
|
|
118
|
+
- [ ] Tests pass (if configured)
|
|
119
|
+
- [ ] Documentation updated
|
|
120
|
+
- [ ] Version type selected (patch/minor/major)
|
|
121
|
+
- [ ] NPM token configured (for GitHub Actions)
|
|
459
122
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
```jsx
|
|
463
|
-
import { LandingPage } from '@snapdragonsnursery/react-components';
|
|
123
|
+
## Troubleshooting
|
|
464
124
|
|
|
465
|
-
|
|
466
|
-
const handleSignIn = () => {
|
|
467
|
-
// Implement your Microsoft authentication logic
|
|
468
|
-
console.log('Sign in clicked');
|
|
469
|
-
};
|
|
125
|
+
### Common Issues
|
|
470
126
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
appDescription="Manage your application efficiently"
|
|
476
|
-
onSignIn={handleSignIn}
|
|
477
|
-
companyName="Your Company"
|
|
478
|
-
/>
|
|
479
|
-
);
|
|
480
|
-
}
|
|
127
|
+
**"Working directory not clean"**
|
|
128
|
+
```bash
|
|
129
|
+
git add .
|
|
130
|
+
git commit -m "Prepare for release"
|
|
481
131
|
```
|
|
482
132
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
| `appName` | `string` | ✅ | - | Name of your application |
|
|
489
|
-
| `appDescription` | `string` | ❌ | "Manage your application efficiently" | App description |
|
|
490
|
-
| `onSignIn` | `function` | ❌ | `() => console.log('Sign in clicked')` | Sign-in callback |
|
|
491
|
-
| `companyName` | `string` | ❌ | "Your Company" | Company name for footer |
|
|
492
|
-
| `backgroundColor` | `string` | ❌ | Blue gradient | CSS background value |
|
|
493
|
-
| `cardClassName` | `string` | ❌ | `""` | Additional CSS classes |
|
|
494
|
-
|
|
495
|
-
### Features
|
|
133
|
+
**"Not on main branch"**
|
|
134
|
+
```bash
|
|
135
|
+
git checkout main
|
|
136
|
+
git pull origin main
|
|
137
|
+
```
|
|
496
138
|
|
|
497
|
-
|
|
498
|
-
-
|
|
499
|
-
-
|
|
500
|
-
- **Customizable**: Configurable logo, colors, and branding
|
|
501
|
-
- **Accessible**: Proper semantic HTML and keyboard navigation
|
|
139
|
+
**"NPM authentication failed"**
|
|
140
|
+
- Check GitHub Secrets → NPM_TOKEN
|
|
141
|
+
- Verify token has publish permissions
|
|
502
142
|
|
|
503
|
-
|
|
143
|
+
**"Version already exists"**
|
|
144
|
+
```bash
|
|
145
|
+
npm run release:minor # Use different version type
|
|
146
|
+
```
|
|
504
147
|
|
|
505
|
-
##
|
|
148
|
+
## Support
|
|
506
149
|
|
|
507
|
-
|
|
150
|
+
For issues with components or release process:
|
|
151
|
+
1. Check component documentation
|
|
152
|
+
2. Review [Release Guide](./RELEASE.md)
|
|
153
|
+
3. Check GitHub Actions logs
|
|
154
|
+
4. Contact the development team
|
|
508
155
|
|
|
509
|
-
|
|
510
|
-
2. **Authentication errors**: Check that all MSAL dependencies are installed and providers are set up correctly
|
|
511
|
-
3. **Theme not working**: Ensure ThemeProvider is wrapping your app and `darkMode: 'class'` is set in Tailwind config
|
|
156
|
+
## Contributing
|
|
512
157
|
|
|
513
|
-
|
|
158
|
+
1. Make changes in feature branch
|
|
159
|
+
2. Test locally
|
|
160
|
+
3. Create pull request
|
|
161
|
+
4. Merge to main
|
|
162
|
+
5. Release using one of the methods above
|
|
514
163
|
|
|
515
|
-
|
|
516
|
-
src/
|
|
517
|
-
├── utils/
|
|
518
|
-
│ ├── authConfig.js
|
|
519
|
-
│ ├── AuthProvider.jsx
|
|
520
|
-
│ └── theme.jsx
|
|
521
|
-
├── components/
|
|
522
|
-
│ └── Navbar.jsx
|
|
523
|
-
├── main.jsx
|
|
524
|
-
├── App.jsx
|
|
525
|
-
└── index.css
|
|
526
|
-
```
|
|
164
|
+
---
|
|
527
165
|
|
|
528
|
-
|
|
166
|
+
**Current Version**: 1.1.0
|
|
167
|
+
**Last Updated**: January 2024
|
package/package.json
CHANGED
package/src/ChildSearchModal.jsx
CHANGED
|
@@ -105,8 +105,11 @@ const ChildSearchModal = ({
|
|
|
105
105
|
|
|
106
106
|
try {
|
|
107
107
|
// Get access token
|
|
108
|
+
const apiBaseUrl = process.env.VITE_COMMON_API_BASE_URL || "https://snaps-common-api.azurewebsites.net";
|
|
109
|
+
const apiScope = apiBaseUrl.replace(/^https?:\/\//, "api://") + "/.default";
|
|
110
|
+
|
|
108
111
|
const response = await instance.acquireTokenSilent({
|
|
109
|
-
scopes: [
|
|
112
|
+
scopes: [apiScope],
|
|
110
113
|
account: accounts[0],
|
|
111
114
|
});
|
|
112
115
|
|