Spit Sign In - Sign Up
All checks were successful
Client Registration / build-deploy (push) Successful in 10s

This commit is contained in:
Grae Jones
2026-03-23 09:39:44 -07:00
parent 3a310c5d3f
commit 732f81333b
5 changed files with 157 additions and 51 deletions

View File

@@ -61,7 +61,7 @@ npm start # http://localhost:3001
Runs in **mock mode** when `API_BASE_URL` is empty in `authConfig.js`. To connect to the real Registration Function, update the constants in `src/auth/authConfig.js`:
```js
export const API_BASE_URL = 'https://portal.positivespend.com';
export const API_BASE_URL = 'https://adpregapi.usimdev.com';
export const API_FUNCTION_KEY = 'your-function-key';
```

File diff suppressed because one or more lines are too long

View File

@@ -1,22 +1,21 @@
/**
* MSAL Configuration for Entra External ID (Customer Identity / CIAM)
* MSAL Configuration for Entra External ID (Customer Identity)
*
* Tenant: Positive Spend Clients
* Domain: positiveclients.onmicrosoft.com
* Tenant ID: cbf8b7d7-1e13-486d-b5b0-287ba79fdf0b
* SPA App: AdPlatform Client SPA (43c493e4-e1ed-4cd7-ab0a-e507e20af724)
* Authority: https://positiveclients.ciamlogin.com/
* This uses the External ID tenant (CIAM) — different from the
* internal Entra tenant used by the Admin/Management console.
*
* TODO: Replace placeholder values with actual External ID tenant details.
*/
export const msalConfig = {
auth: {
clientId: '43c493e4-e1ed-4cd7-ab0a-e507e20af724',
authority: 'https://positiveclients.ciamlogin.com/',
redirectUri: 'https://register.positivespend.com',
postLogoutRedirectUri: 'https://register.positivespend.com',
knownAuthorities: ['positiveclients.ciamlogin.com'],
clientId: '154c9111-14a0-4c0f-8132-7bc68254a74e',
authority: 'https://usimclients.ciamlogin.com/891f98f1-ed34-42a1-9b6c-28b0554d92c2',
redirectUri: window.location.origin,
postLogoutRedirectUri: window.location.origin,
knownAuthorities: ['usimclients.ciamlogin.com'],
},
cache: {
cacheLocation: 'sessionStorage',
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
@@ -25,6 +24,9 @@ export const loginRequest = {
scopes: ['openid', 'profile', 'email'],
};
// Gateway forwards to registration:8080 internally
export const API_BASE_URL = 'https://portal.positivespend.com';
// Registration Function API
export const API_BASE_URL = 'https://adpregapi.usimdev.com';
// Function key for Registration API (AuthorizationLevel.Function)
// TODO: Set this from your Azure Function → App Keys → default host key
export const API_FUNCTION_KEY = '';

View File

@@ -1,53 +1,130 @@
import React from 'react';
import React, { useState } from 'react';
import { useAuth } from '../../auth/AuthProvider';
export default function SignInStep() {
const { signIn, isLoading, error } = useAuth();
const [mode, setMode] = useState(null); // null | 'new' | 'returning'
const providers = (
<div className="provider-list">
<button
className="btn-provider btn-provider-google"
onClick={() => signIn('google')}
disabled={isLoading}
>
<span className="provider-icon">G</span>
{isLoading ? 'Connecting...' : 'Continue with Google'}
</button>
<button
className="btn-provider btn-provider-apple"
onClick={() => signIn('apple')}
disabled={isLoading}
>
<span className="provider-icon">🍎</span>
{isLoading ? 'Connecting...' : 'Continue with Apple'}
</button>
<button
className="btn-provider btn-provider-microsoft"
onClick={() => signIn('microsoft')}
disabled={isLoading}
>
<span className="provider-icon"></span>
{isLoading ? 'Connecting...' : 'Continue with Microsoft'}
</button>
</div>
);
// Landing — user hasn't chosen yet
if (!mode) {
return (
<div className="step-card">
<div className="step-header">
<span className="step-icon">🔷</span>
<h2>Welcome to AdPlatform</h2>
<p className="step-description">
What would you like to do?
</p>
</div>
{error && <div className="error-message">{error}</div>}
<div className="path-choice">
<button
className="btn-path btn-path-primary"
onClick={() => setMode('new')}
>
<span className="path-icon"></span>
<div className="path-text">
<strong>Apply for Access</strong>
<span>New to AdPlatform? Start your registration here.</span>
</div>
<span className="path-arrow"></span>
</button>
<button
className="btn-path btn-path-secondary"
onClick={() => setMode('returning')}
>
<span className="path-icon">🔄</span>
<div className="path-text">
<strong>Check My Application</strong>
<span>Already applied? Sign in to view your status.</span>
</div>
<span className="path-arrow"></span>
</button>
</div>
</div>
);
}
// New applicant — sign up path
if (mode === 'new') {
return (
<div className="step-card">
<button className="btn-back" onClick={() => setMode(null)}> Back</button>
<div className="step-header">
<span className="step-icon"></span>
<h2>Create Your Account</h2>
<p className="step-description">
Choose how you'd like to sign up. We'll create your AdPlatform identity
and walk you through the application.
</p>
</div>
{error && <div className="error-message">{error}</div>}
{providers}
<p className="step-fine-print">
By continuing, you agree to AdPlatform's Terms of Service and Privacy Policy.
Your account will be managed through Microsoft Entra External ID.
</p>
</div>
);
}
// Returning applicant — sign in path
return (
<div className="step-card">
<button className="btn-back" onClick={() => setMode(null)}>← Back</button>
<div className="step-header">
<span className="step-icon">🔐</span>
<h2>Create Your Account</h2>
<span className="step-icon">🔄</span>
<h2>Welcome Back</h2>
<p className="step-description">
Sign in with your preferred provider to get started with AdPlatform.
Sign in with the same account you used when you applied.
We'll pick up right where you left off.
</p>
</div>
{error && <div className="error-message">{error}</div>}
<div className="provider-list">
<button
className="btn-provider btn-provider-google"
onClick={() => signIn('google')}
disabled={isLoading}
>
<span className="provider-icon">G</span>
{isLoading ? 'Connecting...' : 'Continue with Google'}
</button>
<button
className="btn-provider btn-provider-apple"
onClick={() => signIn('apple')}
disabled={isLoading}
>
<span className="provider-icon">🍎</span>
{isLoading ? 'Connecting...' : 'Continue with Apple'}
</button>
<button
className="btn-provider btn-provider-microsoft"
onClick={() => signIn('microsoft')}
disabled={isLoading}
>
<span className="provider-icon"></span>
{isLoading ? 'Connecting...' : 'Continue with Microsoft'}
</button>
</div>
{providers}
<p className="step-fine-print">
By continuing, you agree to AdPlatform's Terms of Service and Privacy Policy.
Your account will be managed through Microsoft Entra External ID.
Use the same provider you signed up with. If you need help, contact
support@positivespend.com.
</p>
</div>
);

View File

@@ -288,6 +288,33 @@ body {
.btn-provider-microsoft { background: #0078d4; color: #fff; border-color: #0078d4; }
.btn-provider-microsoft:hover { background: #006abc; border-color: #006abc; }
/* Two-path landing */
.path-choice { display: flex; flex-direction: column; gap: 12px; margin-top: 8px; }
.btn-path {
display: flex; align-items: center; gap: 16px;
padding: 18px 20px; border-radius: 12px; border: 2px solid var(--border);
background: #fff; cursor: pointer; text-align: left;
transition: border-color 0.15s, box-shadow 0.15s;
width: 100%;
}
.btn-path:hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-light); }
.btn-path-primary:hover { border-color: #0078d4; box-shadow: 0 0 0 3px rgba(0,120,212,0.1); }
.path-icon { font-size: 24px; flex-shrink: 0; }
.path-text { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.path-text strong { font-size: 15px; color: var(--text); font-weight: 600; }
.path-text span { font-size: 13px; color: var(--text-muted); }
.path-arrow { font-size: 18px; color: var(--text-muted); flex-shrink: 0; }
.btn-back {
display: inline-flex; align-items: center; gap: 4px;
background: none; border: none; cursor: pointer;
color: var(--text-muted); font-size: 14px; padding: 0 0 16px 0;
transition: color 0.15s;
}
.btn-back:hover { color: var(--text); }
.provider-icon {
font-size: 18px;
width: 24px;