igniteui-cli 15.2.2 → 15.3.1-beta.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/lib/commands/build.js +7 -12
- package/package.json +7 -7
- package/templates/blazor/igb/projects/ai-config/files/skills/AGENTS.md +0 -5
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/SKILL.md +2 -0
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/charts.md +7 -35
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/data-display.md +0 -54
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/feedback.md +0 -38
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/form-controls.md +0 -68
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/layout-manager.md +1 -124
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/layout.md +0 -62
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/grid-migration.md +322 -0
- package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-theming/SKILL.md +1 -1
- package/templates/react/igr-ts/projects/_base/files/package.json +1 -0
- package/templates/react/igr-ts/projects/_base/files/src/app/app.tsx +4 -2
- package/templates/react/igr-ts/projects/_base/files/src/setupTests.ts +12 -0
- package/templates/react/igr-ts/projects/_base/files/styles.css +6 -0
- package/templates/react/igr-ts/projects/_base_with_home/files/index.html +2 -1
- package/templates/react/igr-ts/projects/_base_with_home/files/src/app/home/home.tsx +60 -10
- package/templates/react/igr-ts/projects/_base_with_home/files/src/app/home/style.module.css +79 -20
- package/templates/react/igr-ts/projects/ai-config/files/skills/grid-lite-to-igr-grid-migration/SKILL.md +274 -0
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-components/SKILL.md +0 -8
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-components/reference/CHARTS-GRIDS.md +6 -36
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-components/reference/COMPONENT-CATALOGUE.md +8 -142
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-components/reference/EVENT-HANDLING.md +2 -0
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-customize-theme/SKILL.md +7 -14
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-customize-theme/reference/CSS-THEMING.md +2 -0
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-customize-theme/reference/MCP-SERVER.md +0 -8
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-generate-from-image-design/SKILL.md +2 -2
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-generate-from-image-design/reference/component-mapping.md +60 -74
- package/templates/react/igr-ts/projects/ai-config/files/skills/igniteui-react-generate-from-image-design/reference/gotchas.md +2 -2
- package/templates/react/igr-ts/projects/empty/index.js +2 -2
- package/templates/react/igr-ts/projects/side-nav/files/src/app/app-routes.tsx +5 -0
- package/templates/react/igr-ts/projects/side-nav/files/src/app/app.css +82 -0
- package/templates/react/igr-ts/projects/side-nav/files/src/app/app.tsx +104 -0
- package/templates/react/igr-ts/projects/side-nav/files/src/app/home/home.tsx +69 -0
- package/templates/react/igr-ts/projects/side-nav/files/src/app/home/style.module.css +105 -0
- package/templates/react/igr-ts/projects/{top-nav → side-nav}/index.d.ts +2 -2
- package/templates/react/igr-ts/projects/{top-nav → side-nav}/index.js +7 -7
- package/templates/react/igr-ts/projects/side-nav-auth/files/index.html +19 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/app-routes.tsx +24 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/app.css +84 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/app.tsx +124 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/AuthContext.tsx +73 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/AuthGuard.tsx +14 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/Login.module.css +93 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/Login.tsx +69 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/LoginBar.module.css +42 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/LoginBar.tsx +44 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/LoginDialog.module.css +14 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/LoginDialog.tsx +49 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/Register.module.css +74 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/components/Register.tsx +67 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/models/external-login.ts +10 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/models/login.ts +4 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/models/register-info.ts +6 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/models/user.ts +19 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/pages/Profile.module.css +87 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/pages/Profile.tsx +42 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/pages/RedirectFacebook.tsx +44 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/pages/RedirectGoogle.tsx +40 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/pages/RedirectMicrosoft.tsx +40 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/authentication.ts +37 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/external-auth-config.ts +44 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/externalAuth.ts +272 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/fakeBackend.ts +88 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/jwtUtil.ts +10 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/pkce.ts +29 -0
- package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/services/userStore.ts +39 -0
- package/templates/react/igr-ts/projects/side-nav-auth/index.d.ts +15 -0
- package/templates/react/igr-ts/projects/side-nav-auth/index.js +46 -0
- package/templates/react/igr-ts/projects/side-nav-mini/files/src/app/app-routes.tsx +5 -0
- package/templates/react/igr-ts/projects/side-nav-mini/files/src/app/app.css +109 -0
- package/templates/react/igr-ts/projects/side-nav-mini/files/src/app/app.test.tsx +20 -0
- package/templates/react/igr-ts/projects/side-nav-mini/files/src/app/app.tsx +81 -0
- package/templates/react/igr-ts/projects/side-nav-mini/files/src/app/home/home.tsx +69 -0
- package/templates/react/igr-ts/projects/side-nav-mini/files/src/app/home/style.module.css +105 -0
- package/templates/react/igr-ts/projects/side-nav-mini/index.d.ts +15 -0
- package/templates/react/igr-ts/projects/side-nav-mini/index.js +46 -0
- package/templates/react/igr-ts/projects/side-nav-mini-auth/files/src/app/app.css +106 -0
- package/templates/react/igr-ts/projects/side-nav-mini-auth/files/src/app/app.tsx +101 -0
- package/templates/react/igr-ts/projects/side-nav-mini-auth/index.d.ts +15 -0
- package/templates/react/igr-ts/projects/side-nav-mini-auth/index.js +50 -0
- package/templates/webcomponents/igc-ts/projects/_base/files/src/app/app.ts +6 -1
- package/templates/webcomponents/igc-ts/projects/_base/files/styles.css +1 -0
- package/templates/webcomponents/igc-ts/projects/_base_with_home/files/index.html +2 -0
- package/templates/webcomponents/igc-ts/projects/_base_with_home/files/src/app/home/home.ts +103 -9
- package/templates/webcomponents/igc-ts/projects/_base_with_home/files/src/assets/wc.png +0 -0
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-choose-components/SKILL.md +122 -160
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-customize-component-theme/SKILL.md +83 -311
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-customize-component-theme/references/mcp-setup.md +69 -0
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-generate-from-image-design/SKILL.md +4 -1
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-generate-from-image-design/references/component-mapping.md +60 -61
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-generate-from-image-design/references/gotchas.md +15 -11
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-migrate-grid-lite-to-premium/SKILL.md +446 -0
- package/templates/webcomponents/igc-ts/projects/ai-config/files/skills/igniteui-wc-optimize-bundle-size/SKILL.md +23 -274
- package/templates/webcomponents/igc-ts/projects/empty/index.js +1 -1
- package/templates/webcomponents/igc-ts/projects/side-nav/files/index.html +21 -0
- package/templates/webcomponents/igc-ts/projects/side-nav/files/src/app/app-routing.ts +9 -0
- package/templates/webcomponents/igc-ts/projects/side-nav/files/src/app/app.ts +192 -22
- package/templates/webcomponents/igc-ts/projects/side-nav/files/src/app/home/home.ts +175 -0
- package/templates/webcomponents/igc-ts/projects/side-nav/index.js +1 -1
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/index.html +25 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/app-routing.ts +37 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/app.ts +251 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/login-bar/login-bar.ts +124 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/login-dialog/login-dialog.ts +253 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/models/external-login.ts +10 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/models/login.ts +4 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/models/register-info.ts +6 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/models/user.ts +19 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/authentication.ts +37 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/external-auth-config.ts +44 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/externalAuth.ts +272 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/fakeBackend.ts +88 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/jwtUtil.ts +10 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/pkce.ts +29 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/authentication/services/userStore.ts +39 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/profile/profile.ts +142 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/redirect/redirect-facebook.ts +57 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/redirect/redirect-google.ts +53 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/files/src/app/redirect/redirect-microsoft.ts +53 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/index.d.ts +15 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-auth/index.js +46 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini/files/src/app/app-routing.ts +13 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini/files/src/app/app.ts +238 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini/index.d.ts +14 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini/index.js +45 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini-auth/files/src/app/app.ts +258 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini-auth/index.d.ts +15 -0
- package/templates/webcomponents/igc-ts/projects/side-nav-mini-auth/index.js +50 -0
- package/templates/react/igr-ts/projects/top-nav/files/src/app/app.css +0 -62
- package/templates/react/igr-ts/projects/top-nav/files/src/app/app.tsx +0 -18
- package/templates/react/igr-ts/projects/top-nav/files/src/components/navigation-header/index.tsx +0 -19
- /package/templates/react/igr-ts/projects/{top-nav → side-nav}/files/src/app/app.test.tsx +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useState, type FormEvent } from 'react';
|
|
2
|
+
import { IgrButton, IgrIcon, IgrInput } from 'igniteui-react';
|
|
3
|
+
import { useAuth } from '../AuthContext';
|
|
4
|
+
import type { RegisterInfo } from '../models/register-info';
|
|
5
|
+
import styles from './Register.module.css';
|
|
6
|
+
|
|
7
|
+
interface RegisterProps {
|
|
8
|
+
onLogin: () => void;
|
|
9
|
+
onSuccess: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Register({ onLogin, onSuccess }: RegisterProps) {
|
|
13
|
+
const { register } = useAuth();
|
|
14
|
+
const [givenName, setGivenName] = useState('');
|
|
15
|
+
const [familyName, setFamilyName] = useState('');
|
|
16
|
+
const [email, setEmail] = useState('');
|
|
17
|
+
const [password, setPassword] = useState('');
|
|
18
|
+
const [error, setError] = useState('');
|
|
19
|
+
|
|
20
|
+
const canSubmit = givenName.trim() !== '' && email.trim() !== '' && password !== '';
|
|
21
|
+
|
|
22
|
+
const handleSubmit = async (e: FormEvent) => {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
setError('');
|
|
25
|
+
const data: RegisterInfo = {
|
|
26
|
+
given_name: givenName,
|
|
27
|
+
family_name: familyName,
|
|
28
|
+
email,
|
|
29
|
+
password
|
|
30
|
+
};
|
|
31
|
+
const err = await register(data);
|
|
32
|
+
if (err) {
|
|
33
|
+
setError(err);
|
|
34
|
+
} else {
|
|
35
|
+
setPassword('');
|
|
36
|
+
onSuccess();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<form className={styles.form} onSubmit={handleSubmit} noValidate>
|
|
42
|
+
<IgrInput outlined type="text" name="given_name" label="First Name" autoComplete="given-name" required={true}
|
|
43
|
+
value={givenName} onInput={(e: any) => setGivenName(e.detail ?? '')}>
|
|
44
|
+
<IgrIcon slot="suffix" name="assignment_ind" collection="material" />
|
|
45
|
+
</IgrInput>
|
|
46
|
+
<IgrInput outlined type="text" name="family_name" label="Last Name" autoComplete="family-name"
|
|
47
|
+
value={familyName} onInput={(e: any) => setFamilyName(e.detail ?? '')}>
|
|
48
|
+
<IgrIcon slot="suffix" name="assignment_ind" collection="material" />
|
|
49
|
+
</IgrInput>
|
|
50
|
+
<IgrInput outlined type="email" name="email" label="Email" autoComplete="email" required={true}
|
|
51
|
+
value={email} onInput={(e: any) => setEmail(e.detail ?? '')}>
|
|
52
|
+
<IgrIcon slot="suffix" name="account_circle" collection="material" />
|
|
53
|
+
</IgrInput>
|
|
54
|
+
<IgrInput outlined type="password" name="password" label="Password" autoComplete="new-password" required={true}
|
|
55
|
+
value={password} onInput={(e: any) => setPassword(e.detail ?? '')}>
|
|
56
|
+
<IgrIcon slot="suffix" name="lock" collection="material" />
|
|
57
|
+
</IgrInput>
|
|
58
|
+
{error && <p className={styles.error}>{error}</p>}
|
|
59
|
+
<div className={styles.actions}>
|
|
60
|
+
<IgrButton variant="contained" type="submit" className={styles.submitBtn} disabled={!canSubmit}>
|
|
61
|
+
<span>Sign Up</span>
|
|
62
|
+
</IgrButton>
|
|
63
|
+
<a className={styles.linkBtn} onClick={onLogin} role="button" tabIndex={0}>Have an account?</a>
|
|
64
|
+
</div>
|
|
65
|
+
</form>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** User profile returned by a social (external) auth provider. */
|
|
2
|
+
export interface ExternalLogin {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
email?: string; // not always present use id as fallback key
|
|
6
|
+
given_name?: string;
|
|
7
|
+
family_name?: string;
|
|
8
|
+
picture?: string;
|
|
9
|
+
externalToken: string;
|
|
10
|
+
}
|
package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/models/user.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Data transfer model expected from backend API JWT-s */
|
|
2
|
+
export interface UserJWT {
|
|
3
|
+
exp: number;
|
|
4
|
+
name: string;
|
|
5
|
+
given_name: string;
|
|
6
|
+
family_name: string;
|
|
7
|
+
email: string;
|
|
8
|
+
picture?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Client user model */
|
|
12
|
+
export interface User extends UserJWT {
|
|
13
|
+
token: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LoginResult {
|
|
17
|
+
user?: User;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
display: flex;
|
|
3
|
+
justify-content: center;
|
|
4
|
+
padding: 48px 16px;
|
|
5
|
+
width: 100%;
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.card {
|
|
10
|
+
align-self: flex-start;
|
|
11
|
+
width: 100%;
|
|
12
|
+
max-width: 640px;
|
|
13
|
+
background: #fff;
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, .08);
|
|
16
|
+
padding: 32px;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.header {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: 20px;
|
|
24
|
+
padding-bottom: 24px;
|
|
25
|
+
border-bottom: 1px solid #d7eaf8;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.avatar {
|
|
29
|
+
flex: 0 0 auto;
|
|
30
|
+
--ig-avatar-background: #e0f2ff;
|
|
31
|
+
--ig-avatar-color: #0075d2;
|
|
32
|
+
--ig-avatar-size: 4rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.intro {
|
|
36
|
+
min-width: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.status {
|
|
40
|
+
margin: 0 0 4px;
|
|
41
|
+
color: #000;
|
|
42
|
+
font-size: .875rem;
|
|
43
|
+
font-weight: 700;
|
|
44
|
+
text-transform: uppercase;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.name {
|
|
48
|
+
margin: 0;
|
|
49
|
+
overflow-wrap: anywhere;
|
|
50
|
+
color: #09f;
|
|
51
|
+
font-size: 2rem;
|
|
52
|
+
font-weight: 600;
|
|
53
|
+
line-height: 1.2;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.description {
|
|
57
|
+
margin: 8px 0 0;
|
|
58
|
+
color: #000;
|
|
59
|
+
font-size: 1rem;
|
|
60
|
+
line-height: 1.5;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.details {
|
|
64
|
+
margin: 28px 0 0;
|
|
65
|
+
padding: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.row {
|
|
69
|
+
display: grid;
|
|
70
|
+
grid-template-columns: 140px minmax(0, 1fr);
|
|
71
|
+
gap: 24px;
|
|
72
|
+
padding: 14px 0;
|
|
73
|
+
border-bottom: 1px solid #eef3f7;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.dt {
|
|
77
|
+
color: rgba(0, 0, 0, .62);
|
|
78
|
+
font-size: .875rem;
|
|
79
|
+
font-weight: 600;
|
|
80
|
+
margin: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.dd {
|
|
84
|
+
margin: 0;
|
|
85
|
+
font-size: 1rem;
|
|
86
|
+
color: #2d2d2d;
|
|
87
|
+
}
|
package/templates/react/igr-ts/projects/side-nav-auth/files/src/app/authentication/pages/Profile.tsx
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IgrAvatar } from 'igniteui-react';
|
|
2
|
+
import { useAuth } from '../AuthContext';
|
|
3
|
+
import styles from './Profile.module.css';
|
|
4
|
+
|
|
5
|
+
export default function Profile() {
|
|
6
|
+
const { currentUser } = useAuth();
|
|
7
|
+
const initials = ((currentUser?.given_name?.[0] ?? '') + (currentUser?.family_name?.[0] ?? '')).toUpperCase() || 'U';
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div className={styles.container}>
|
|
11
|
+
<div className={styles.card}>
|
|
12
|
+
<div className={styles.header}>
|
|
13
|
+
<IgrAvatar
|
|
14
|
+
className={styles.avatar}
|
|
15
|
+
shape="circle"
|
|
16
|
+
initials={initials}
|
|
17
|
+
src={currentUser?.picture ?? ''}
|
|
18
|
+
/>
|
|
19
|
+
<div className={styles.intro}>
|
|
20
|
+
<p className={styles.status}>Signed in</p>
|
|
21
|
+
<h1 className={styles.name}>{currentUser?.name || 'Your profile'}</h1>
|
|
22
|
+
<p className={styles.description}>Your account details are available on this protected route.</p>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<dl className={styles.details}>
|
|
26
|
+
<div className={styles.row}>
|
|
27
|
+
<dt className={styles.dt}>First name</dt>
|
|
28
|
+
<dd className={styles.dd}>{currentUser?.given_name || 'Not provided'}</dd>
|
|
29
|
+
</div>
|
|
30
|
+
<div className={styles.row}>
|
|
31
|
+
<dt className={styles.dt}>Last name</dt>
|
|
32
|
+
<dd className={styles.dd}>{currentUser?.family_name || 'Not provided'}</dd>
|
|
33
|
+
</div>
|
|
34
|
+
<div className={styles.row}>
|
|
35
|
+
<dt className={styles.dt}>Email</dt>
|
|
36
|
+
<dd className={styles.dd}>{currentUser?.email || 'No email available'}</dd>
|
|
37
|
+
</div>
|
|
38
|
+
</dl>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import { ExternalAuth } from '../services/externalAuth';
|
|
4
|
+
import { useAuth } from '../AuthContext';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handles the Facebook login redirect.
|
|
8
|
+
* Facebook uses a popup (JS SDK) instead of PKCE, so this page reads the profile
|
|
9
|
+
* that was stored in sessionStorage during the FB.login() callback.
|
|
10
|
+
*/
|
|
11
|
+
export default function RedirectFacebook() {
|
|
12
|
+
const { loginWith } = useAuth();
|
|
13
|
+
const navigate = useNavigate();
|
|
14
|
+
const [error, setError] = useState('');
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
(async () => {
|
|
18
|
+
try {
|
|
19
|
+
const externalUser = await ExternalAuth.handleRedirect('facebook');
|
|
20
|
+
const err = await loginWith(externalUser);
|
|
21
|
+
if (err) {
|
|
22
|
+
setError(err);
|
|
23
|
+
} else {
|
|
24
|
+
navigate('/auth/profile');
|
|
25
|
+
}
|
|
26
|
+
} catch (e: any) {
|
|
27
|
+
console.error('Facebook sign-in failed:', e);
|
|
28
|
+
setError('Facebook sign-in failed. Please try again.');
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
if (error) {
|
|
35
|
+
return (
|
|
36
|
+
<div style={{ padding: '2rem', color: '#d32f2f' }}>
|
|
37
|
+
<p>{error}</p>
|
|
38
|
+
<button onClick={() => navigate('/')}>Back to Home</button>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return <p style={{ padding: '2rem' }}>Signing in with Facebook…</p>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import { ExternalAuth } from '../services/externalAuth';
|
|
4
|
+
import { useAuth } from '../AuthContext';
|
|
5
|
+
|
|
6
|
+
/** Handles the OAuth redirect from Google. Exchanges the authorization code for a user profile. */
|
|
7
|
+
export default function RedirectGoogle() {
|
|
8
|
+
const { loginWith } = useAuth();
|
|
9
|
+
const navigate = useNavigate();
|
|
10
|
+
const [error, setError] = useState('');
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
(async () => {
|
|
14
|
+
try {
|
|
15
|
+
const externalUser = await ExternalAuth.handleRedirect('google');
|
|
16
|
+
const err = await loginWith(externalUser);
|
|
17
|
+
if (err) {
|
|
18
|
+
setError(err);
|
|
19
|
+
} else {
|
|
20
|
+
navigate('/auth/profile');
|
|
21
|
+
}
|
|
22
|
+
} catch (e: any) {
|
|
23
|
+
console.error('Google sign-in failed:', e);
|
|
24
|
+
setError('Google sign-in failed. Please try again.');
|
|
25
|
+
}
|
|
26
|
+
})();
|
|
27
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
if (error) {
|
|
31
|
+
return (
|
|
32
|
+
<div style={{ padding: '2rem', color: '#d32f2f' }}>
|
|
33
|
+
<p>{error}</p>
|
|
34
|
+
<button onClick={() => navigate('/')}>Back to Home</button>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return <p style={{ padding: '2rem' }}>Signing in with Google…</p>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import { ExternalAuth } from '../services/externalAuth';
|
|
4
|
+
import { useAuth } from '../AuthContext';
|
|
5
|
+
|
|
6
|
+
/** Handles the OAuth redirect from Microsoft. Exchanges the authorization code for a user profile. */
|
|
7
|
+
export default function RedirectMicrosoft() {
|
|
8
|
+
const { loginWith } = useAuth();
|
|
9
|
+
const navigate = useNavigate();
|
|
10
|
+
const [error, setError] = useState('');
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
(async () => {
|
|
14
|
+
try {
|
|
15
|
+
const externalUser = await ExternalAuth.handleRedirect('microsoft');
|
|
16
|
+
const err = await loginWith(externalUser);
|
|
17
|
+
if (err) {
|
|
18
|
+
setError(err);
|
|
19
|
+
} else {
|
|
20
|
+
navigate('/auth/profile');
|
|
21
|
+
}
|
|
22
|
+
} catch (e: any) {
|
|
23
|
+
console.error('Microsoft sign-in failed:', e);
|
|
24
|
+
setError('Microsoft sign-in failed. Please try again.');
|
|
25
|
+
}
|
|
26
|
+
})();
|
|
27
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
if (error) {
|
|
31
|
+
return (
|
|
32
|
+
<div style={{ padding: '2rem', color: '#d32f2f' }}>
|
|
33
|
+
<p>{error}</p>
|
|
34
|
+
<button onClick={() => navigate('/')}>Back to Home</button>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return <p style={{ padding: '2rem' }}>Signing in with Microsoft…</p>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Login } from '../models/login';
|
|
2
|
+
import type { RegisterInfo } from '../models/register-info';
|
|
3
|
+
import type { ExternalLogin } from '../models/external-login';
|
|
4
|
+
import type { LoginResult } from '../models/user';
|
|
5
|
+
import { parseUser } from './jwtUtil';
|
|
6
|
+
import { fakeLogin, fakeRegister, fakeExtLogin } from './fakeBackend';
|
|
7
|
+
|
|
8
|
+
/** Authentication service — swap fakeLogin/fakeRegister for real API calls when ready. */
|
|
9
|
+
export const Authentication = {
|
|
10
|
+
async login(data: Login): Promise<LoginResult> {
|
|
11
|
+
try {
|
|
12
|
+
const token = await fakeLogin(data);
|
|
13
|
+
return { user: parseUser(token) };
|
|
14
|
+
} catch (e: any) {
|
|
15
|
+
return { error: e.message };
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
async register(data: RegisterInfo): Promise<LoginResult> {
|
|
20
|
+
try {
|
|
21
|
+
const token = await fakeRegister(data);
|
|
22
|
+
return { user: parseUser(token) };
|
|
23
|
+
} catch (e: any) {
|
|
24
|
+
return { error: e.message };
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/** Send user info from a social provider to the external login endpoint. */
|
|
29
|
+
async loginWith(data: ExternalLogin): Promise<LoginResult> {
|
|
30
|
+
try {
|
|
31
|
+
const token = fakeExtLogin(data);
|
|
32
|
+
return { user: parseUser(token) };
|
|
33
|
+
} catch (e: any) {
|
|
34
|
+
return { error: e.message };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Social login configuration.
|
|
2
|
+
// To enable a provider, set its entry in oauthConfig below with your real credentials
|
|
3
|
+
// from the provider's developer console.
|
|
4
|
+
//
|
|
5
|
+
// Redirect URIs to register in each provider's app settings:
|
|
6
|
+
// {your-origin}/auth/redirect-google
|
|
7
|
+
// {your-origin}/auth/redirect-facebook
|
|
8
|
+
// {your-origin}/auth/redirect-microsoft
|
|
9
|
+
//
|
|
10
|
+
// Developer consoles:
|
|
11
|
+
// Google: https://console.cloud.google.com/apis/credentials
|
|
12
|
+
// Microsoft: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps
|
|
13
|
+
// Facebook: https://developers.facebook.com/apps
|
|
14
|
+
|
|
15
|
+
export type OAuthProvider = 'google' | 'facebook' | 'microsoft';
|
|
16
|
+
|
|
17
|
+
export interface OAuthConfig {
|
|
18
|
+
google?: { clientId: string };
|
|
19
|
+
|
|
20
|
+
// tenantId defaults to 'common' (multi-tenant). Set it for single-tenant apps.
|
|
21
|
+
// IMPORTANT: The redirect URI must be registered as a SPA redirect URI in Azure
|
|
22
|
+
// (not "Web"), otherwise the token exchange will fail with a CORS error.
|
|
23
|
+
// See: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow
|
|
24
|
+
microsoft?: { clientId: string; tenantId?: string };
|
|
25
|
+
|
|
26
|
+
// Facebook login uses the JS SDK (popup flow). The SDK script must be loaded in
|
|
27
|
+
// index.html (see below). In the Facebook app dashboard you must also:
|
|
28
|
+
// - Enable "Login with the JavaScript SDK"
|
|
29
|
+
// - Add your domain to "Allowed Domains for the JavaScript SDK"
|
|
30
|
+
// - Add the redirect URI to "Valid OAuth Redirect URIs"
|
|
31
|
+
// - Serve the app over HTTPS
|
|
32
|
+
// See: https://developers.facebook.com/docs/facebook-login/web
|
|
33
|
+
facebook?: { clientId: string };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Active OAuth configuration — fill in the providers you want to enable, for example:
|
|
37
|
+
//
|
|
38
|
+
// export const oauthConfig: OAuthConfig = {
|
|
39
|
+
// google: { clientId: 'YOUR_GOOGLE_CLIENT_ID' },
|
|
40
|
+
// microsoft: { clientId: 'YOUR_AZURE_APP_CLIENT_ID', tenantId: 'common' },
|
|
41
|
+
// // Note: Facebook requires HTTPS even for local dev - use ngrok or a local SSL proxy.
|
|
42
|
+
// facebook: { clientId: 'YOUR_FACEBOOK_APP_ID' },
|
|
43
|
+
// };
|
|
44
|
+
export const oauthConfig: OAuthConfig = {};
|