@oxyhq/services 26.0.4 → 26.1.0
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/commonjs/ui/components/OxyAuthChooser.js +11 -11
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +34 -2
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +17 -0
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +3 -5
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/components/OxyAuthChooser.js +12 -12
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +34 -2
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js +1 -1
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +16 -0
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +3 -5
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +4 -0
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +2 -0
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +4 -0
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +2 -0
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ui/components/OxyAuthChooser.tsx +19 -12
- package/src/ui/components/OxySignInButton.tsx +43 -1
- package/src/ui/components/ProfileButton.tsx +1 -1
- package/src/ui/navigation/accountDialogManager.ts +17 -0
- package/src/ui/screens/AccountSettingsScreen.tsx +3 -4
|
@@ -12,6 +12,7 @@ import { useAuthStore } from '../stores/authStore';
|
|
|
12
12
|
import { useShallow } from 'zustand/react/shallow';
|
|
13
13
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
14
14
|
import { Button, type ButtonVariant } from '@oxyhq/bloom/button';
|
|
15
|
+
import { toast } from '@oxyhq/bloom/toast';
|
|
15
16
|
import { useOxy } from '../context/OxyContext';
|
|
16
17
|
import { useI18n } from '../hooks/useI18n';
|
|
17
18
|
import { LogoIcon } from './logo/LogoIcon';
|
|
@@ -201,6 +202,24 @@ export const OxySignInButton: React.FC<OxySignInButtonProps> = ({
|
|
|
201
202
|
return promise;
|
|
202
203
|
}, [clientId, oxyServices]);
|
|
203
204
|
|
|
205
|
+
// A press that cannot reach a sign-in surface must SAY so. Without this the
|
|
206
|
+
// only trace of an aborted sign-in was a console line, so the button read as
|
|
207
|
+
// simply dead — the SDK owns this so no relying party has to wire it up.
|
|
208
|
+
// `ToastOutlet` is already mounted by `OxyProvider`.
|
|
209
|
+
const notifyNotConfigured = useCallback(
|
|
210
|
+
(appName: string) => {
|
|
211
|
+
toast.error(t('signin.errors.notConfigured'), {
|
|
212
|
+
description: t('signin.errors.notConfiguredDescription', { app: appName }),
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
[t],
|
|
216
|
+
);
|
|
217
|
+
const notifyFailed = useCallback(() => {
|
|
218
|
+
toast.error(t('signin.errors.failed'), {
|
|
219
|
+
description: t('signin.errors.failedDescription'),
|
|
220
|
+
});
|
|
221
|
+
}, [t]);
|
|
222
|
+
|
|
204
223
|
// Official / first-party surface: the in-app account + sign-in dialog.
|
|
205
224
|
const startOfficialSignIn = useCallback(() => {
|
|
206
225
|
openAccountDialog('signin');
|
|
@@ -227,6 +246,7 @@ export const OxySignInButton: React.FC<OxySignInButtonProps> = ({
|
|
|
227
246
|
undefined,
|
|
228
247
|
{ component: 'OxySignInButton', clientId, application: app.name },
|
|
229
248
|
);
|
|
249
|
+
notifyNotConfigured(app.name);
|
|
230
250
|
return;
|
|
231
251
|
}
|
|
232
252
|
|
|
@@ -245,6 +265,7 @@ export const OxySignInButton: React.FC<OxySignInButtonProps> = ({
|
|
|
245
265
|
{ component: 'OxySignInButton', application: app.name },
|
|
246
266
|
result.description,
|
|
247
267
|
);
|
|
268
|
+
notifyFailed();
|
|
248
269
|
}
|
|
249
270
|
return;
|
|
250
271
|
}
|
|
@@ -267,6 +288,7 @@ export const OxySignInButton: React.FC<OxySignInButtonProps> = ({
|
|
|
267
288
|
'OxySignInButton: native third-party sign-in cannot complete without an `onOAuthResult` handler; the code exchange is the RP\'s responsibility (state + code_verifier were not surfaced)',
|
|
268
289
|
{ component: 'OxySignInButton', application: app.name },
|
|
269
290
|
);
|
|
291
|
+
notifyNotConfigured(app.name);
|
|
270
292
|
},
|
|
271
293
|
[
|
|
272
294
|
clientId,
|
|
@@ -275,6 +297,8 @@ export const OxySignInButton: React.FC<OxySignInButtonProps> = ({
|
|
|
275
297
|
startOfficialSignIn,
|
|
276
298
|
startWebOAuthSignIn,
|
|
277
299
|
shouldPreOpenPopup,
|
|
300
|
+
notifyNotConfigured,
|
|
301
|
+
notifyFailed,
|
|
278
302
|
],
|
|
279
303
|
);
|
|
280
304
|
|
|
@@ -316,11 +340,29 @@ export const OxySignInButton: React.FC<OxySignInButtonProps> = ({
|
|
|
316
340
|
}
|
|
317
341
|
closeOAuthPopup(popup);
|
|
318
342
|
startOfficialSignIn();
|
|
343
|
+
} catch (error) {
|
|
344
|
+
// `handlePress` fires this without awaiting, so an unexpected
|
|
345
|
+
// throw (a rejected native auth session, a crypto failure) would
|
|
346
|
+
// otherwise vanish into an unhandled rejection with the button
|
|
347
|
+
// left looking inert.
|
|
348
|
+
closeOAuthPopup(popup);
|
|
349
|
+
logger.error(
|
|
350
|
+
'OxySignInButton: sign-in routing threw; sign-in aborted',
|
|
351
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
352
|
+
{ component: 'OxySignInButton', clientId },
|
|
353
|
+
);
|
|
354
|
+
notifyFailed();
|
|
319
355
|
} finally {
|
|
320
356
|
routingRef.current = false;
|
|
321
357
|
}
|
|
322
358
|
},
|
|
323
|
-
[
|
|
359
|
+
[
|
|
360
|
+
resolvePublicApplication,
|
|
361
|
+
startOfficialSignIn,
|
|
362
|
+
startThirdPartyOAuth,
|
|
363
|
+
clientId,
|
|
364
|
+
notifyFailed,
|
|
365
|
+
],
|
|
324
366
|
);
|
|
325
367
|
|
|
326
368
|
// Defer to a caller-supplied handler, otherwise route by application type.
|
|
@@ -134,7 +134,7 @@ const ProfileButton: React.FC<ProfileButtonProps> = ({
|
|
|
134
134
|
}, [openAccountDialog]);
|
|
135
135
|
|
|
136
136
|
useEffect(() => {
|
|
137
|
-
if (!onNavigateManage && !onAddAccount && !onNavigateProfile) {
|
|
137
|
+
if (!onNavigateManage && !onAddAccount && !onNavigateProfile && !menuItems?.length) {
|
|
138
138
|
return undefined;
|
|
139
139
|
}
|
|
140
140
|
return registerAccountDialogConsumerHooks({
|
|
@@ -45,6 +45,13 @@ export interface AccountDialogConsumerHooks {
|
|
|
45
45
|
let controls: AccountDialogControls | null = null;
|
|
46
46
|
let consumerHooks: AccountDialogConsumerHooks | null = null;
|
|
47
47
|
const visibilityListeners = new Set<(visible: boolean) => void>();
|
|
48
|
+
const consumerHookListeners = new Set<() => void>();
|
|
49
|
+
|
|
50
|
+
function notifyConsumerHookListeners(): void {
|
|
51
|
+
for (const listener of consumerHookListeners) {
|
|
52
|
+
listener();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
48
55
|
|
|
49
56
|
export function registerAccountDialogControls(next: AccountDialogControls): () => void {
|
|
50
57
|
controls = next;
|
|
@@ -60,9 +67,11 @@ export function registerAccountDialogConsumerHooks(
|
|
|
60
67
|
next: AccountDialogConsumerHooks | null,
|
|
61
68
|
): () => void {
|
|
62
69
|
consumerHooks = next;
|
|
70
|
+
notifyConsumerHookListeners();
|
|
63
71
|
return () => {
|
|
64
72
|
if (consumerHooks === next) {
|
|
65
73
|
consumerHooks = null;
|
|
74
|
+
notifyConsumerHookListeners();
|
|
66
75
|
}
|
|
67
76
|
};
|
|
68
77
|
}
|
|
@@ -71,6 +80,14 @@ export function getAccountDialogConsumerHooks(): AccountDialogConsumerHooks | nu
|
|
|
71
80
|
return consumerHooks;
|
|
72
81
|
}
|
|
73
82
|
|
|
83
|
+
/** Subscribe to consumer-hook registration changes (menu items, manage/add overrides). */
|
|
84
|
+
export function subscribeToAccountDialogConsumerHooks(listener: () => void): () => void {
|
|
85
|
+
consumerHookListeners.add(listener);
|
|
86
|
+
return () => {
|
|
87
|
+
consumerHookListeners.delete(listener);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
74
91
|
/** Open the account dialog on `view` (default `accounts`). No-op before mount. */
|
|
75
92
|
export function openAccountDialog(view?: AccountDialogView): void {
|
|
76
93
|
controls?.open(view);
|
|
@@ -143,11 +143,10 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, nav
|
|
|
143
143
|
const handleSave = useCallback(() => {
|
|
144
144
|
const trimmed = displayName.trim();
|
|
145
145
|
if (!trimmed || displayNameError) return;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const last = nameParts.length > 1 ? nameParts.slice(1).join(' ') : undefined;
|
|
146
|
+
// Managed accounts (org / project / bot / channel) have a title, not a
|
|
147
|
+
// given-and-family name — persist the explicit displayName column.
|
|
149
148
|
updateMutation.mutate({
|
|
150
|
-
name: {
|
|
149
|
+
name: { displayName: trimmed },
|
|
151
150
|
bio: bio.trim() ? bio.trim() : null,
|
|
152
151
|
});
|
|
153
152
|
}, [displayName, displayNameError, bio, updateMutation]);
|