Compare commits
4 Commits
981117629a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e96bd61a | ||
|
|
7925b45d76 | ||
|
|
d8dda59f4c | ||
|
|
541251f065 |
2
Client-Home/dist/bundle.js
vendored
2
Client-Home/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
|||||||
// - APP_URL: the URL that should open the *app* (direct entry / dashboard).
|
// - APP_URL: the URL that should open the *app* (direct entry / dashboard).
|
||||||
// - REGISTRATION_URL: the URL to your external registration experience.
|
// - REGISTRATION_URL: the URL to your external registration experience.
|
||||||
//
|
//
|
||||||
// Tip: keep these as full absolute URLs.
|
// Tip: keep these as full absolute
|
||||||
|
|
||||||
export const APP_URL = 'https://adpclient.usimdev.com/';
|
export const APP_URL = 'https://client.positivespend.com/';
|
||||||
export const REGISTRATION_URL = 'https://adpregist.usimdev.com/';
|
export const REGISTRATION_URL = 'https://register.positivespend.com/';
|
||||||
|
|||||||
2
Client-Registration/dist/bundle.js
vendored
2
Client-Registration/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -41,12 +41,17 @@ export function useAuth() {
|
|||||||
|
|
||||||
// ── Map ID token claims → user object ─────────────────────────────────────
|
// ── Map ID token claims → user object ─────────────────────────────────────
|
||||||
function claimsToUser(claims, provider) {
|
function claimsToUser(claims, provider) {
|
||||||
|
const firstName = claims.given_name ?? null;
|
||||||
|
const surname = claims.family_name ?? null;
|
||||||
|
const displayName = claims.name
|
||||||
|
?? [firstName, surname].filter(Boolean).join(' ')
|
||||||
|
?? null;
|
||||||
return {
|
return {
|
||||||
entraSubjectId: claims.oid ?? claims.sub ?? null,
|
entraSubjectId: claims.oid ?? claims.sub ?? null,
|
||||||
email: claims.email ?? claims.preferred_username ?? null,
|
email: claims.email ?? claims.preferred_username ?? null,
|
||||||
displayName: claims.name ?? null,
|
displayName,
|
||||||
firstName: claims.given_name ?? null,
|
firstName,
|
||||||
surname: claims.family_name ?? null,
|
surname,
|
||||||
provider: provider ?? 'unknown',
|
provider: provider ?? 'unknown',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ export default function ContactStep() {
|
|||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { contactData, setContactData, saveContact, goBack, loading, error } = useRegistration();
|
const { contactData, setContactData, saveContact, goBack, loading, error } = useRegistration();
|
||||||
|
|
||||||
// Pre-fill from auth claims on mount
|
// Pre-fill from CIAM claims on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
setContactData(prev => ({
|
setContactData(prev => ({
|
||||||
contactName: prev.contactName || user.displayName || '',
|
firstName: prev.firstName || user.firstName || '',
|
||||||
|
lastName: prev.lastName || user.surname || '',
|
||||||
contactEmail: prev.contactEmail || user.email || '',
|
contactEmail: prev.contactEmail || user.email || '',
|
||||||
contactPhone: prev.contactPhone || '',
|
contactPhone: prev.contactPhone || '',
|
||||||
}));
|
}));
|
||||||
@@ -39,7 +40,9 @@ export default function ContactStep() {
|
|||||||
|
|
||||||
{user && (
|
{user && (
|
||||||
<div className="info-card">
|
<div className="info-card">
|
||||||
<div className="info-card-primary">{user.displayName}</div>
|
<div className="info-card-primary">
|
||||||
|
{[user.firstName, user.surname].filter(Boolean).join(' ') || user.displayName || user.email}
|
||||||
|
</div>
|
||||||
<div className="info-card-secondary">{user.email}</div>
|
<div className="info-card-secondary">{user.email}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -47,26 +50,41 @@ export default function ContactStep() {
|
|||||||
{error && <div className="error-message">{error}</div>}
|
{error && <div className="error-message">{error}</div>}
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="form-row">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="contactName">Full Name <span className="required">*</span></label>
|
<label htmlFor="firstName">First Name <span className="required">*</span></label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="contactName"
|
id="firstName"
|
||||||
name="contactName"
|
name="firstName"
|
||||||
value={contactData.contactName}
|
value={contactData.firstName || ''}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder="Jane Smith"
|
placeholder="Jane"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="lastName">Last Name <span className="required">*</span></label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="lastName"
|
||||||
|
name="lastName"
|
||||||
|
value={contactData.lastName || ''}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Smith"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="contactEmail">Email <span className="required">*</span></label>
|
<label htmlFor="contactEmail">Email <span className="required">*</span></label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
id="contactEmail"
|
id="contactEmail"
|
||||||
name="contactEmail"
|
name="contactEmail"
|
||||||
value={contactData.contactEmail}
|
value={contactData.contactEmail || ''}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder="jane@example.com"
|
placeholder="jane@example.com"
|
||||||
required
|
required
|
||||||
@@ -79,7 +97,7 @@ export default function ContactStep() {
|
|||||||
type="tel"
|
type="tel"
|
||||||
id="contactPhone"
|
id="contactPhone"
|
||||||
name="contactPhone"
|
name="contactPhone"
|
||||||
value={contactData.contactPhone}
|
value={contactData.contactPhone || ''}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder="(555) 123-4567"
|
placeholder="(555) 123-4567"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ export function RegistrationProvider({ children }) {
|
|||||||
|
|
||||||
// Form data — maps to RegisterRequest model fields (minus entraSubjectId)
|
// Form data — maps to RegisterRequest model fields (minus entraSubjectId)
|
||||||
const [contactData, setContactData] = useState({
|
const [contactData, setContactData] = useState({
|
||||||
contactName: '',
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
contactEmail: '',
|
contactEmail: '',
|
||||||
contactPhone: '',
|
contactPhone: '',
|
||||||
});
|
});
|
||||||
@@ -83,8 +84,9 @@ export function RegistrationProvider({ children }) {
|
|||||||
// ─── Validation ─────────────────────────────────────────────────────
|
// ─── Validation ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
const validateContact = useCallback(() => {
|
const validateContact = useCallback(() => {
|
||||||
if (!contactData.contactName.trim()) return 'Contact name is required';
|
if (!contactData.firstName?.trim()) return 'First name is required';
|
||||||
if (!contactData.contactEmail.trim()) return 'Email is required';
|
if (!contactData.lastName?.trim()) return 'Last name is required';
|
||||||
|
if (!contactData.contactEmail?.trim()) return 'Email is required';
|
||||||
return null;
|
return null;
|
||||||
}, [contactData]);
|
}, [contactData]);
|
||||||
|
|
||||||
@@ -132,6 +134,8 @@ export function RegistrationProvider({ children }) {
|
|||||||
const request = {
|
const request = {
|
||||||
...contactData,
|
...contactData,
|
||||||
...businessData,
|
...businessData,
|
||||||
|
// Combine for server-side contactName field
|
||||||
|
contactName: [contactData.firstName, contactData.lastName].filter(Boolean).join(' '),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pre-fill email from auth if the user left it blank
|
// Pre-fill email from auth if the user left it blank
|
||||||
|
|||||||
@@ -326,6 +326,16 @@ body {
|
|||||||
Forms
|
Forms
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .form-group {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
2
Client-Tech/dist/bundle.js
vendored
2
Client-Tech/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,20 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* authConfig.js — Tech Client (Staff Plane)
|
* authConfig.js — Tech Client (Staff Plane)
|
||||||
*
|
|
||||||
* ┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
* │ PRODUCTION MIGRATION — only these values change at handoff: │
|
|
||||||
* │ │
|
|
||||||
* │ STAFF_AUTHORITY → 'https://login.microsoftonline.com/{ORG_TENANT}' │
|
|
||||||
* │ STAFF_TENANT_ID → new company org tenant ID │
|
|
||||||
* │ STAFF_CLIENT_ID → staff app registration in org tenant │
|
|
||||||
* │ │
|
|
||||||
* │ No other code changes required anywhere. │
|
|
||||||
* └─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
*
|
|
||||||
* DEV NOTE: Staff currently authenticate against the CIAM tenant (same as
|
|
||||||
* clients) because no org tenant exists yet. The login screen looks identical
|
|
||||||
* to the client login — this is cosmetic only. API isolation is enforced by
|
|
||||||
* audience: staff tokens are rejected by Gateway, client tokens by Management.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ── Staff Identity Config ─────────────────────────────────────────────────────
|
// ── Staff Identity Config ─────────────────────────────────────────────────────
|
||||||
@@ -22,9 +7,11 @@
|
|||||||
const STAFF_TENANT_ID = 'f56a3c51-9b5c-4356-920f-b4dcf932a96b';
|
const STAFF_TENANT_ID = 'f56a3c51-9b5c-4356-920f-b4dcf932a96b';
|
||||||
const STAFF_CLIENT_ID = '217928a9-4591-4dff-9f09-5b233824cf4f';
|
const STAFF_CLIENT_ID = '217928a9-4591-4dff-9f09-5b233824cf4f';
|
||||||
|
|
||||||
// PROD: swap to → 'https://login.microsoftonline.com/' + STAFF_TENANT_ID
|
|
||||||
const STAFF_AUTHORITY = 'https://login.microsoftonline.com/' + STAFF_TENANT_ID;
|
const STAFF_AUTHORITY = 'https://login.microsoftonline.com/' + STAFF_TENANT_ID;
|
||||||
|
|
||||||
|
// Management Staff API — resource the Tech SPA requests a token for
|
||||||
|
const MGMT_APP_ID = 'af95fa13-2ef4-4911-b137-7acc6a784cfa';
|
||||||
|
|
||||||
// ── MSAL Config ───────────────────────────────────────────────────────────────
|
// ── MSAL Config ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const msalConfig = {
|
export const msalConfig = {
|
||||||
@@ -33,7 +20,7 @@ export const msalConfig = {
|
|||||||
authority: STAFF_AUTHORITY,
|
authority: STAFF_AUTHORITY,
|
||||||
redirectUri: window.location.origin,
|
redirectUri: window.location.origin,
|
||||||
postLogoutRedirectUri: window.location.origin,
|
postLogoutRedirectUri: window.location.origin,
|
||||||
navigateToLoginRequestUrl: true,
|
navigateToLoginRequestUrl: false, // ← was true, caused the loop
|
||||||
},
|
},
|
||||||
cache: {
|
cache: {
|
||||||
cacheLocation: 'sessionStorage',
|
cacheLocation: 'sessionStorage',
|
||||||
@@ -50,19 +37,18 @@ export const msalConfig = {
|
|||||||
case 3: console.debug(message); break;
|
case 3: console.debug(message); break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
logLevel: 3,
|
logLevel: 1, // warn + error only in prod
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loginRequest = {
|
export const loginRequest = {
|
||||||
scopes: ["api://4e4d69c3-558a-4a27-a689-17bd397175e5/access_as_user"]
|
scopes: [`api://${MGMT_APP_ID}/access_as_user`] // ← fixed
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── API Endpoints ─────────────────────────────────────────────────────────────
|
// ── API Endpoints ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const API_BASE = 'https://adpapi.usimdev.com'; // Gateway API
|
export const API_BASE = 'https://portal.positivespend.com'; // ← fixed
|
||||||
export const MGMT_BASE = 'https://adpmgmt.usimdev.com'; // Management API
|
export const MGMT_BASE = 'https://mgmt.positivespend.com'; // ← fixed
|
||||||
|
|
||||||
// Legacy — kept for backward compatibility with apiClient.js
|
|
||||||
export const SESSION_ENDPOINT = `${API_BASE}/api/auth/session`;
|
export const SESSION_ENDPOINT = `${API_BASE}/api/auth/session`;
|
||||||
Reference in New Issue
Block a user