@oxy.so/services 11.2.0 → 11.3.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/commonjs/ui/boot/runProviderColdBoot.js +47 -3
- package/lib/commonjs/ui/boot/runProviderColdBoot.js.map +1 -1
- package/lib/commonjs/ui/components/organizations/OrganizationClaimReview.js +208 -0
- package/lib/commonjs/ui/components/organizations/OrganizationClaimReview.js.map +1 -0
- package/lib/commonjs/ui/components/organizations/OrganizationClaims.js +77 -0
- package/lib/commonjs/ui/components/organizations/OrganizationClaims.js.map +1 -0
- package/lib/commonjs/ui/components/organizations/OrganizationDirectorySearch.js +218 -0
- package/lib/commonjs/ui/components/organizations/OrganizationDirectorySearch.js.map +1 -0
- package/lib/commonjs/ui/components/organizations/OrganizationSettings.js +147 -0
- package/lib/commonjs/ui/components/organizations/OrganizationSettings.js.map +1 -0
- package/lib/commonjs/ui/components/organizations/OrganizationTypePicker.js +34 -0
- package/lib/commonjs/ui/components/organizations/OrganizationTypePicker.js.map +1 -0
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +14 -5
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/CreateAccountScreen.js +148 -115
- package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +13 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/boot/runProviderColdBoot.js +47 -3
- package/lib/module/ui/boot/runProviderColdBoot.js.map +1 -1
- package/lib/module/ui/components/organizations/OrganizationClaimReview.js +205 -0
- package/lib/module/ui/components/organizations/OrganizationClaimReview.js.map +1 -0
- package/lib/module/ui/components/organizations/OrganizationClaims.js +73 -0
- package/lib/module/ui/components/organizations/OrganizationClaims.js.map +1 -0
- package/lib/module/ui/components/organizations/OrganizationDirectorySearch.js +215 -0
- package/lib/module/ui/components/organizations/OrganizationDirectorySearch.js.map +1 -0
- package/lib/module/ui/components/organizations/OrganizationSettings.js +143 -0
- package/lib/module/ui/components/organizations/OrganizationSettings.js.map +1 -0
- package/lib/module/ui/components/organizations/OrganizationTypePicker.js +30 -0
- package/lib/module/ui/components/organizations/OrganizationTypePicker.js.map +1 -0
- package/lib/module/ui/screens/AccountSettingsScreen.js +14 -5
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/CreateAccountScreen.js +149 -115
- package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +13 -1
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationClaimReview.d.ts +3 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationClaimReview.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationClaims.d.ts +2 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationClaims.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationDirectorySearch.d.ts +6 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationDirectorySearch.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationSettings.d.ts +5 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationSettings.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationTypePicker.d.ts +7 -0
- package/lib/typescript/commonjs/ui/components/organizations/OrganizationTypePicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +3 -2
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/usePersonalPlans.d.ts +2 -2
- package/lib/typescript/commonjs/ui/icons/Ionicons.d.ts +1 -1
- package/lib/typescript/commonjs/ui/icons/MaterialCommunityIcons.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/organizations/OrganizationClaimReview.d.ts +3 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationClaimReview.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationClaims.d.ts +2 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationClaims.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationDirectorySearch.d.ts +6 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationDirectorySearch.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationSettings.d.ts +5 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationSettings.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationTypePicker.d.ts +7 -0
- package/lib/typescript/module/ui/components/organizations/OrganizationTypePicker.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +3 -2
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/usePersonalPlans.d.ts +2 -2
- package/lib/typescript/module/ui/icons/Ionicons.d.ts +1 -1
- package/lib/typescript/module/ui/icons/MaterialCommunityIcons.d.ts +1 -1
- package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/ui/boot/__tests__/coldBootNoIdpRedirect.test.ts +166 -3
- package/src/ui/boot/runProviderColdBoot.ts +49 -4
- package/src/ui/components/organizations/OrganizationClaimReview.tsx +218 -0
- package/src/ui/components/organizations/OrganizationClaims.tsx +67 -0
- package/src/ui/components/organizations/OrganizationDirectorySearch.tsx +228 -0
- package/src/ui/components/organizations/OrganizationSettings.tsx +131 -0
- package/src/ui/components/organizations/OrganizationTypePicker.tsx +31 -0
- package/src/ui/screens/AccountSettingsScreen.tsx +22 -4
- package/src/ui/screens/CreateAccountScreen.tsx +177 -124
- package/src/ui/screens/ManageAccountScreen.tsx +18 -0
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ORGANIZATION_NAME_MAX_LENGTH,
|
|
4
|
+
organizationNameSchema,
|
|
5
|
+
type OrganizationType,
|
|
6
|
+
} from '@oxy.so/contracts';
|
|
7
|
+
import { OrganizationDirectorySearch } from '../components/organizations/OrganizationDirectorySearch';
|
|
8
|
+
import { OrganizationTypePicker } from '../components/organizations/OrganizationTypePicker';
|
|
2
9
|
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
3
10
|
import { View, ActivityIndicator } from 'react-native';
|
|
4
11
|
import Ionicons from '../icons/Ionicons';
|
|
@@ -114,19 +121,21 @@ const ACCOUNT_CATEGORY_OPTIONS: readonly AccountCategoryId[] = SELECTABLE_ACCOUN
|
|
|
114
121
|
*/
|
|
115
122
|
const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, parentAccountId }) => {
|
|
116
123
|
const bloomTheme = useTheme();
|
|
117
|
-
const { oxyServices, createAccount, switchToAccount } = useOxy();
|
|
124
|
+
const { oxyServices, createAccount, switchToAccount, user, canUsePrivateApi } = useOxy();
|
|
118
125
|
const { t, locale } = useI18n();
|
|
119
126
|
|
|
120
|
-
useSurfaceHeader({
|
|
121
|
-
title: t('accounts.create.title') || 'Create account',
|
|
122
|
-
subtitle:
|
|
123
|
-
t('accounts.create.subtitle') ||
|
|
124
|
-
'Create an account you control. It will have its own profile, members, and apps.',
|
|
125
|
-
});
|
|
126
|
-
|
|
127
127
|
const parentId = typeof parentAccountId === 'string' ? parentAccountId : undefined;
|
|
128
128
|
|
|
129
129
|
const [kind, setKind] = useState<CreatableAccountKind>('project');
|
|
130
|
+
const [organizationType, setOrganizationType] = useState<OrganizationType>('business');
|
|
131
|
+
const [newOrganization, setNewOrganization] = useState(false);
|
|
132
|
+
const findingOrganization = kind === 'organization' && !newOrganization;
|
|
133
|
+
useSurfaceHeader({
|
|
134
|
+
title: t(findingOrganization ? 'organizationDirectory.title' : 'accounts.create.title'),
|
|
135
|
+
subtitle: t(
|
|
136
|
+
findingOrganization ? 'organizationDirectory.searchHint' : 'accounts.create.subtitle',
|
|
137
|
+
),
|
|
138
|
+
});
|
|
130
139
|
/**
|
|
131
140
|
* ORDER IS THE DATA: index 0 is the primary category. Selecting appends,
|
|
132
141
|
* de-selecting removes, and neither sorts — so the list the user assembles is
|
|
@@ -254,6 +263,7 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
254
263
|
const handleKindChange = useCallback(
|
|
255
264
|
(nextKind: CreatableAccountKind) => {
|
|
256
265
|
setKind(nextKind);
|
|
266
|
+
setNewOrganization(false);
|
|
257
267
|
if (!username) return;
|
|
258
268
|
const proposed = nextKind === 'bot' ? applyBotUsernameSuffix(username) : username;
|
|
259
269
|
setUsername(proposed);
|
|
@@ -270,6 +280,14 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
270
280
|
setDisplayNameError('');
|
|
271
281
|
return;
|
|
272
282
|
}
|
|
283
|
+
if (kind === 'organization') {
|
|
284
|
+
setDisplayNameError(
|
|
285
|
+
organizationNameSchema.safeParse(trimmed).success
|
|
286
|
+
? ''
|
|
287
|
+
: t('organizationDirectory.invalidName'),
|
|
288
|
+
);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
273
291
|
const nameParts = trimmed.split(/\s+/);
|
|
274
292
|
const firstName = nameParts[0] || '';
|
|
275
293
|
const lastName = nameParts.length > 1 ? nameParts.slice(1).join(' ') : '';
|
|
@@ -280,7 +298,7 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
280
298
|
: '',
|
|
281
299
|
);
|
|
282
300
|
},
|
|
283
|
-
[t],
|
|
301
|
+
[kind, t],
|
|
284
302
|
);
|
|
285
303
|
|
|
286
304
|
/**
|
|
@@ -301,10 +319,12 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
301
319
|
}, []);
|
|
302
320
|
|
|
303
321
|
const canCreate =
|
|
322
|
+
canUsePrivateApi &&
|
|
304
323
|
usernameStatus === 'available' &&
|
|
305
324
|
displayName.trim().length > 0 &&
|
|
306
325
|
!displayNameError &&
|
|
307
|
-
!isCreating
|
|
326
|
+
!isCreating &&
|
|
327
|
+
(kind !== 'organization' || newOrganization);
|
|
308
328
|
|
|
309
329
|
const handleCreate = useCallback(async () => {
|
|
310
330
|
if (!canCreate) return;
|
|
@@ -313,6 +333,7 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
313
333
|
try {
|
|
314
334
|
const input: CreateAccountInput = {
|
|
315
335
|
kind,
|
|
336
|
+
...(kind === 'organization' ? { organizationType } : {}),
|
|
316
337
|
username,
|
|
317
338
|
name: { displayName: displayName.trim() },
|
|
318
339
|
bio: bio.trim() || undefined,
|
|
@@ -352,6 +373,7 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
352
373
|
}, [
|
|
353
374
|
canCreate,
|
|
354
375
|
kind,
|
|
376
|
+
organizationType,
|
|
355
377
|
accountCategories,
|
|
356
378
|
username,
|
|
357
379
|
displayName,
|
|
@@ -405,128 +427,159 @@ const CreateAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, paren
|
|
|
405
427
|
})}
|
|
406
428
|
</SettingsListGroup>
|
|
407
429
|
|
|
408
|
-
{
|
|
430
|
+
{kind === 'organization' && !newOrganization ? (
|
|
431
|
+
<OrganizationDirectorySearch
|
|
432
|
+
key={user?.id}
|
|
433
|
+
onCreateAccount={(name, type) => {
|
|
434
|
+
handleDisplayNameChange(name);
|
|
435
|
+
setOrganizationType(type);
|
|
436
|
+
setNewOrganization(true);
|
|
437
|
+
}}
|
|
438
|
+
/>
|
|
439
|
+
) : (
|
|
440
|
+
<>
|
|
441
|
+
{kind === 'organization' ? (
|
|
442
|
+
<>
|
|
443
|
+
<Button appearance="outline" onPress={() => setNewOrganization(false)}>
|
|
444
|
+
{t('organizationDirectory.back')}
|
|
445
|
+
</Button>
|
|
446
|
+
<OrganizationTypePicker
|
|
447
|
+
value={organizationType}
|
|
448
|
+
onChange={setOrganizationType}
|
|
449
|
+
disabled={isCreating}
|
|
450
|
+
/>
|
|
451
|
+
</>
|
|
452
|
+
) : null}
|
|
453
|
+
{/* Categories — multi-select, shown for every kind this screen can create
|
|
409
454
|
(they are all non-personal). The badge on a selected row is its
|
|
410
455
|
POSITION, so the primary is legible as "1" rather than being a rule the
|
|
411
456
|
user has to be told. */}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
457
|
+
<View className="gap-space-4">
|
|
458
|
+
<SettingsListGroup title={t('accounts.create.accountCategory.label')}>
|
|
459
|
+
{ACCOUNT_CATEGORY_OPTIONS.map((option) => {
|
|
460
|
+
const position = accountCategories.indexOf(option);
|
|
461
|
+
const selected = position >= 0;
|
|
462
|
+
const label = accountCategoryLabel(locale, option);
|
|
463
|
+
return (
|
|
464
|
+
<SettingsListItem
|
|
465
|
+
key={option}
|
|
466
|
+
title={label}
|
|
467
|
+
disabled={!selected && accountCategories.length >= MAX_ACCOUNT_CATEGORIES}
|
|
468
|
+
onPress={() => toggleAccountCategory(option)}
|
|
469
|
+
showChevron={false}
|
|
470
|
+
rightElement={
|
|
471
|
+
selected ? (
|
|
472
|
+
<Text className="text-caption-1 font-semibold text-primary">
|
|
473
|
+
{position + 1}
|
|
474
|
+
</Text>
|
|
475
|
+
) : undefined
|
|
476
|
+
}
|
|
477
|
+
accessibilityLabel={label}
|
|
478
|
+
/>
|
|
479
|
+
);
|
|
480
|
+
})}
|
|
481
|
+
</SettingsListGroup>
|
|
482
|
+
<Text className="text-caption font-caption text-text-tertiary px-space-4">
|
|
483
|
+
{t('accounts.create.accountCategory.hint', { max: MAX_ACCOUNT_CATEGORIES })}
|
|
484
|
+
</Text>
|
|
485
|
+
</View>
|
|
486
|
+
|
|
487
|
+
{/* Details — a grouped section card hosting the form fields */}
|
|
488
|
+
<SettingsListGroup title={t('accounts.create.detailsSection') || 'Details'}>
|
|
489
|
+
<View className="p-space-16 gap-space-16">
|
|
490
|
+
{/* Username */}
|
|
491
|
+
<View className="gap-space-8">
|
|
492
|
+
<TextField isInvalid={usernameIsInvalid}>
|
|
493
|
+
<TextFieldInput
|
|
494
|
+
floatingLabel
|
|
495
|
+
label={t('accounts.create.username.label') || 'Username'}
|
|
496
|
+
value={username}
|
|
497
|
+
onChangeText={handleUsernameChange}
|
|
498
|
+
isInvalid={usernameIsInvalid}
|
|
499
|
+
autoCapitalize="none"
|
|
500
|
+
autoCorrect={false}
|
|
501
|
+
autoComplete="off"
|
|
502
|
+
maxLength={USERNAME_MAX_LENGTH}
|
|
503
|
+
/>
|
|
504
|
+
</TextField>
|
|
505
|
+
{usernameStatus === 'checking' || usernameMessage ? (
|
|
506
|
+
<View className="flex-row items-center gap-space-4 px-space-4">
|
|
507
|
+
{usernameStatus === 'checking' ? (
|
|
508
|
+
<ActivityIndicator size="small" color={bloomTheme.colors.primary} />
|
|
509
|
+
) : usernameStatus === 'available' ? (
|
|
510
|
+
<Ionicons
|
|
511
|
+
name="checkmark-circle"
|
|
512
|
+
size={16}
|
|
513
|
+
color={bloomTheme.colors.success}
|
|
514
|
+
/>
|
|
515
|
+
) : usernameIsInvalid ? (
|
|
516
|
+
<Ionicons name="alert-circle" size={16} color={bloomTheme.colors.negative} />
|
|
517
|
+
) : null}
|
|
518
|
+
{usernameMessage ? (
|
|
519
|
+
<Text className="text-caption font-caption" style={{ color: statusColor }}>
|
|
520
|
+
{usernameMessage}
|
|
521
|
+
</Text>
|
|
522
|
+
) : null}
|
|
523
|
+
</View>
|
|
468
524
|
) : null}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
525
|
+
</View>
|
|
526
|
+
|
|
527
|
+
{/* Display Name */}
|
|
528
|
+
<View className="gap-space-4">
|
|
529
|
+
<TextField isInvalid={Boolean(displayNameError)}>
|
|
530
|
+
<TextFieldInput
|
|
531
|
+
floatingLabel
|
|
532
|
+
label={t('accounts.create.displayName.label') || 'Display name'}
|
|
533
|
+
value={displayName}
|
|
534
|
+
onChangeText={handleDisplayNameChange}
|
|
535
|
+
isInvalid={Boolean(displayNameError)}
|
|
536
|
+
maxLength={
|
|
537
|
+
kind === 'organization' ? ORGANIZATION_NAME_MAX_LENGTH : DISPLAY_NAME_MAX
|
|
538
|
+
}
|
|
539
|
+
/>
|
|
540
|
+
</TextField>
|
|
541
|
+
{displayNameError ? (
|
|
542
|
+
<Text className="text-caption font-caption text-negative px-space-4">
|
|
543
|
+
{displayNameError}
|
|
472
544
|
</Text>
|
|
473
545
|
) : null}
|
|
474
546
|
</View>
|
|
475
|
-
) : null}
|
|
476
|
-
</View>
|
|
477
|
-
|
|
478
|
-
{/* Display Name */}
|
|
479
|
-
<View className="gap-space-4">
|
|
480
|
-
<TextField isInvalid={Boolean(displayNameError)}>
|
|
481
|
-
<TextFieldInput
|
|
482
|
-
floatingLabel
|
|
483
|
-
label={t('accounts.create.displayName.label') || 'Display name'}
|
|
484
|
-
value={displayName}
|
|
485
|
-
onChangeText={handleDisplayNameChange}
|
|
486
|
-
isInvalid={Boolean(displayNameError)}
|
|
487
|
-
maxLength={DISPLAY_NAME_MAX}
|
|
488
|
-
/>
|
|
489
|
-
</TextField>
|
|
490
|
-
{displayNameError ? (
|
|
491
|
-
<Text className="text-caption font-caption text-negative px-space-4">
|
|
492
|
-
{displayNameError}
|
|
493
|
-
</Text>
|
|
494
|
-
) : null}
|
|
495
|
-
</View>
|
|
496
547
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
548
|
+
{/* Bio */}
|
|
549
|
+
<View className="gap-space-4">
|
|
550
|
+
<TextField>
|
|
551
|
+
<TextFieldInput
|
|
552
|
+
floatingLabel
|
|
553
|
+
label={t('accounts.create.bio.label') || 'Bio (optional)'}
|
|
554
|
+
value={bio}
|
|
555
|
+
onChangeText={setBio}
|
|
556
|
+
maxLength={BIO_MAX}
|
|
557
|
+
multiline
|
|
558
|
+
numberOfLines={3}
|
|
559
|
+
textAlignVertical="top"
|
|
560
|
+
/>
|
|
561
|
+
</TextField>
|
|
562
|
+
<Text className="text-caption font-caption text-text-tertiary px-space-4 text-right">
|
|
563
|
+
{bio.length}/{BIO_MAX}
|
|
564
|
+
</Text>
|
|
565
|
+
</View>
|
|
566
|
+
</View>
|
|
567
|
+
</SettingsListGroup>
|
|
568
|
+
|
|
569
|
+
{/* Create Button */}
|
|
570
|
+
<Button
|
|
571
|
+
appearance="solid"
|
|
572
|
+
tone="accent"
|
|
573
|
+
onPress={handleCreate}
|
|
574
|
+
disabled={!canCreate}
|
|
575
|
+
loading={isCreating}
|
|
576
|
+
accessibilityLabel={title}
|
|
577
|
+
className="w-full"
|
|
578
|
+
>
|
|
579
|
+
{title}
|
|
580
|
+
</Button>
|
|
581
|
+
</>
|
|
582
|
+
)}
|
|
530
583
|
</View>
|
|
531
584
|
);
|
|
532
585
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { OrganizationClaimReview } from '../components/organizations/OrganizationClaimReview';
|
|
2
|
+
import { OrganizationClaims } from '../components/organizations/OrganizationClaims';
|
|
1
3
|
import type React from 'react';
|
|
2
4
|
import { useCallback, useMemo, useState } from 'react';
|
|
3
5
|
import { View, StyleSheet, ActivityIndicator, Linking, Platform } from 'react-native';
|
|
@@ -396,6 +398,22 @@ const ManageAccountScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, navig
|
|
|
396
398
|
/>
|
|
397
399
|
</SettingsListGroup>
|
|
398
400
|
|
|
401
|
+
{user?.kind === 'organization' ? (
|
|
402
|
+
<SettingsListGroup title={t('organizationDirectory.title')}>
|
|
403
|
+
<SettingsListItem
|
|
404
|
+
title={t('organizationDirectory.view')}
|
|
405
|
+
onPress={() => navigate?.('AccountSettings', { accountId: user.id })}
|
|
406
|
+
/>
|
|
407
|
+
</SettingsListGroup>
|
|
408
|
+
) : null}
|
|
409
|
+
|
|
410
|
+
{user?.kind === 'personal' ? (
|
|
411
|
+
<>
|
|
412
|
+
<OrganizationClaims key={user.id} />
|
|
413
|
+
<OrganizationClaimReview key={`review:${user.id}`} />
|
|
414
|
+
</>
|
|
415
|
+
) : null}
|
|
416
|
+
|
|
399
417
|
{/* Sessions section */}
|
|
400
418
|
<SettingsListGroup title={t('manageAccount.sections.sessions') || 'Sessions & devices'}>
|
|
401
419
|
{deviceSessionsLoading ? (
|