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`: 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 ```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'; export const API_FUNCTION_KEY = 'your-function-key';
``` ```

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -1,21 +1,11 @@
import React from 'react'; import React, { useState } from 'react';
import { useAuth } from '../../auth/AuthProvider'; import { useAuth } from '../../auth/AuthProvider';
export default function SignInStep() { export default function SignInStep() {
const { signIn, isLoading, error } = useAuth(); const { signIn, isLoading, error } = useAuth();
const [mode, setMode] = useState(null); // null | 'new' | 'returning'
return ( const providers = (
<div className="step-card">
<div className="step-header">
<span className="step-icon">🔐</span>
<h2>Create Your Account</h2>
<p className="step-description">
Sign in with your preferred provider to get started with AdPlatform.
</p>
</div>
{error && <div className="error-message">{error}</div>}
<div className="provider-list"> <div className="provider-list">
<button <button
className="btn-provider btn-provider-google" className="btn-provider btn-provider-google"
@@ -44,6 +34,68 @@ export default function SignInStep() {
{isLoading ? 'Connecting...' : 'Continue with Microsoft'} {isLoading ? 'Connecting...' : 'Continue with Microsoft'}
</button> </button>
</div> </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"> <p className="step-fine-print">
By continuing, you agree to AdPlatform's Terms of Service and Privacy Policy. By continuing, you agree to AdPlatform's Terms of Service and Privacy Policy.
@@ -51,4 +103,29 @@ export default function SignInStep() {
</p> </p>
</div> </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>Welcome Back</h2>
<p className="step-description">
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>}
{providers}
<p className="step-fine-print">
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 { background: #0078d4; color: #fff; border-color: #0078d4; }
.btn-provider-microsoft:hover { background: #006abc; border-color: #006abc; } .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 { .provider-icon {
font-size: 18px; font-size: 18px;
width: 24px; width: 24px;