@oxy.so/services 1.2.0 → 2.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/README.md +11 -1
- package/lib/commonjs/ui/components/BenefitList.js +93 -0
- package/lib/commonjs/ui/components/BenefitList.js.map +1 -0
- package/lib/commonjs/ui/components/FollowTargetButton.js +1 -1
- package/lib/commonjs/ui/components/FollowTargetButton.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +36 -35
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +1 -17
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/passkeyFlow.js +2 -28
- package/lib/commonjs/ui/context/passkeyFlow.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js +10 -10
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js +6 -6
- package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +5 -5
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js +13 -13
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js.map +1 -1
- package/lib/module/ui/components/BenefitList.js +89 -0
- package/lib/module/ui/components/BenefitList.js.map +1 -0
- package/lib/module/ui/components/FollowTargetButton.js +1 -1
- package/lib/module/ui/components/FollowTargetButton.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +36 -35
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +2 -18
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/passkeyFlow.js +2 -27
- package/lib/module/ui/context/passkeyFlow.js.map +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js +6 -6
- package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/module/ui/screens/LearnMoreUsernamesScreen.js +6 -6
- package/lib/module/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustAboutScreen.js +7 -7
- package/lib/module/ui/screens/trust/TrustAboutScreen.js.map +1 -1
- package/lib/typescript/commonjs/ui/components/BenefitList.d.ts +25 -0
- package/lib/typescript/commonjs/ui/components/BenefitList.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +31 -12
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +0 -8
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/passkeyFlow.d.ts +2 -21
- package/lib/typescript/commonjs/ui/context/passkeyFlow.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/BenefitList.d.ts +25 -0
- package/lib/typescript/module/ui/components/BenefitList.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts +31 -12
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +0 -8
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/passkeyFlow.d.ts +2 -21
- package/lib/typescript/module/ui/context/passkeyFlow.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ui/components/BenefitList.tsx +111 -0
- package/src/ui/components/FollowTargetButton.tsx +1 -1
- package/src/ui/components/OxySignInButton.tsx +73 -41
- package/src/ui/context/OxyContext.tsx +1 -19
- package/src/ui/context/__tests__/passkeyFlow.test.ts +2 -65
- package/src/ui/context/oxyContextTypes.ts +0 -6
- package/src/ui/context/passkeyFlow.ts +2 -39
- package/src/ui/screens/AccountVerificationScreen.tsx +6 -6
- package/src/ui/screens/LearnMoreUsernamesScreen.tsx +6 -6
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +1 -1
- package/src/ui/screens/trust/TrustAboutScreen.tsx +7 -7
|
@@ -95,7 +95,7 @@ import { DEFAULT_SESSION_VALIDITY_MS } from './oxyContextHelpers';
|
|
|
95
95
|
// never dereferenced at module scope here.
|
|
96
96
|
import { useFollow } from '../hooks/useFollow';
|
|
97
97
|
import { commitDeviceSetAndResolve } from './commitSessionFlow';
|
|
98
|
-
import { runPasskeyLogin,
|
|
98
|
+
import { runPasskeyLogin, runPasskeyAdd } from './passkeyFlow';
|
|
99
99
|
import {
|
|
100
100
|
isPasskeySupported,
|
|
101
101
|
runRegistrationCeremony,
|
|
@@ -959,22 +959,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
959
959
|
[oxyServices, authStore, commitSession],
|
|
960
960
|
);
|
|
961
961
|
|
|
962
|
-
// Create a brand-new account whose first auth method is a passkey.
|
|
963
|
-
const registerWithPasskey = useCallback(
|
|
964
|
-
async (params: { username: string; deviceName?: string }): Promise<void> => {
|
|
965
|
-
await runPasskeyRegister({
|
|
966
|
-
isSupported: isPasskeySupported,
|
|
967
|
-
getRegisterOptions: (username) => oxyServices.webauthnRegisterOptions(username),
|
|
968
|
-
runCeremony: runRegistrationCeremony,
|
|
969
|
-
registerVerify: (response, envelope) => oxyServices.webauthnRegisterVerify(response, envelope),
|
|
970
|
-
commit: (input) => commitSession(input, { activate: true }),
|
|
971
|
-
username: params.username,
|
|
972
|
-
deviceName: params.deviceName,
|
|
973
|
-
});
|
|
974
|
-
},
|
|
975
|
-
[oxyServices, commitSession],
|
|
976
|
-
);
|
|
977
|
-
|
|
978
962
|
// Add a passkey to the already-signed-in account (bearer present). No new
|
|
979
963
|
// session is committed — just refresh the linked auth-methods list.
|
|
980
964
|
const addPasskey = useCallback(
|
|
@@ -1265,7 +1249,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
1265
1249
|
getPublicKey,
|
|
1266
1250
|
signIn,
|
|
1267
1251
|
signInWithPasskey,
|
|
1268
|
-
registerWithPasskey,
|
|
1269
1252
|
addPasskey,
|
|
1270
1253
|
removePasskey,
|
|
1271
1254
|
revokeSuspiciousSignIn,
|
|
@@ -1323,7 +1306,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
1323
1306
|
getPublicKey,
|
|
1324
1307
|
signIn,
|
|
1325
1308
|
signInWithPasskey,
|
|
1326
|
-
registerWithPasskey,
|
|
1327
1309
|
addPasskey,
|
|
1328
1310
|
removePasskey,
|
|
1329
1311
|
revokeSuspiciousSignIn,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `passkeyFlow` — the pure, deps-injected passkey (WebAuthn) orchestration that
|
|
3
|
-
* backs `useOxy().signInWithPasskey` / `
|
|
3
|
+
* backs `useOxy().signInWithPasskey` / `addPasskey`.
|
|
4
4
|
*
|
|
5
5
|
* These tests assert the fixed `options → ceremony → verify → commit` ordering,
|
|
6
6
|
* the exact `commitSession` input projected from a session-arm login result, the
|
|
@@ -12,11 +12,9 @@
|
|
|
12
12
|
import type { LoginSessionResult } from '@oxy.so/contracts';
|
|
13
13
|
import {
|
|
14
14
|
runPasskeyLogin,
|
|
15
|
-
|
|
16
|
-
runPasskeyAdd,
|
|
15
|
+
runPasskeyAdd,
|
|
17
16
|
PASSKEY_UNSUPPORTED_MESSAGE,
|
|
18
17
|
type RunPasskeyLoginDeps,
|
|
19
|
-
type RunPasskeyRegisterDeps,
|
|
20
18
|
type RunPasskeyAddDeps,
|
|
21
19
|
type PasskeyRegisterVerifyResult,
|
|
22
20
|
} from '../passkeyFlow';
|
|
@@ -122,67 +120,6 @@ describe('runPasskeyLogin', () => {
|
|
|
122
120
|
});
|
|
123
121
|
});
|
|
124
122
|
|
|
125
|
-
describe('runPasskeyRegister', () => {
|
|
126
|
-
const buildDeps = (
|
|
127
|
-
order: string[],
|
|
128
|
-
overrides: Partial<RunPasskeyRegisterDeps> = {},
|
|
129
|
-
): RunPasskeyRegisterDeps => ({
|
|
130
|
-
isSupported: jest.fn(() => true),
|
|
131
|
-
getRegisterOptions: jest.fn(async (username) => {
|
|
132
|
-
order.push('getRegisterOptions');
|
|
133
|
-
expect(username).toBe('newuser');
|
|
134
|
-
return { challenge: 'reg-opts' };
|
|
135
|
-
}),
|
|
136
|
-
runCeremony: jest.fn(async () => {
|
|
137
|
-
order.push('runCeremony');
|
|
138
|
-
return { id: 'attestation' };
|
|
139
|
-
}),
|
|
140
|
-
registerVerify: jest.fn(async () => {
|
|
141
|
-
order.push('registerVerify');
|
|
142
|
-
return sessionResult;
|
|
143
|
-
}),
|
|
144
|
-
commit: jest.fn(async () => {
|
|
145
|
-
order.push('commit');
|
|
146
|
-
}),
|
|
147
|
-
username: 'newuser',
|
|
148
|
-
deviceName: 'My Laptop',
|
|
149
|
-
...overrides,
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('creates the account (signup branch) and commits the minted session', async () => {
|
|
153
|
-
const order: string[] = [];
|
|
154
|
-
const deps = buildDeps(order);
|
|
155
|
-
|
|
156
|
-
await runPasskeyRegister(deps);
|
|
157
|
-
|
|
158
|
-
expect(order).toEqual(['getRegisterOptions', 'runCeremony', 'registerVerify', 'commit']);
|
|
159
|
-
expect(deps.registerVerify).toHaveBeenCalledWith(
|
|
160
|
-
{ id: 'attestation' },
|
|
161
|
-
{ username: 'newuser', deviceName: 'My Laptop' },
|
|
162
|
-
);
|
|
163
|
-
expect(deps.commit).toHaveBeenCalledWith(expectedCommitInput);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('throws (no commit) when verify returns a link branch instead of a session', async () => {
|
|
167
|
-
const order: string[] = [];
|
|
168
|
-
const deps = buildDeps(order, {
|
|
169
|
-
registerVerify: jest.fn(async () => linkResult),
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
await expect(runPasskeyRegister(deps)).rejects.toThrow(/did not establish a session/i);
|
|
173
|
-
expect(deps.commit).not.toHaveBeenCalled();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('throws and touches nothing when passkeys are unsupported', async () => {
|
|
177
|
-
const order: string[] = [];
|
|
178
|
-
const deps = buildDeps(order, { isSupported: jest.fn(() => false) });
|
|
179
|
-
|
|
180
|
-
await expect(runPasskeyRegister(deps)).rejects.toThrow(PASSKEY_UNSUPPORTED_MESSAGE);
|
|
181
|
-
expect(deps.getRegisterOptions).not.toHaveBeenCalled();
|
|
182
|
-
expect(deps.commit).not.toHaveBeenCalled();
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
123
|
describe('runPasskeyAdd', () => {
|
|
187
124
|
const buildDeps = (
|
|
188
125
|
order: string[],
|
|
@@ -88,12 +88,6 @@ export interface OxyContextState {
|
|
|
88
88
|
deviceFingerprint?: string;
|
|
89
89
|
}) => Promise<void>;
|
|
90
90
|
|
|
91
|
-
/**
|
|
92
|
-
* Create a brand-new account whose first authentication method is a passkey.
|
|
93
|
-
* WEB-ONLY — throws on native or an unsupported browser.
|
|
94
|
-
*/
|
|
95
|
-
registerWithPasskey: (params: { username: string; deviceName?: string }) => Promise<void>;
|
|
96
|
-
|
|
97
91
|
/**
|
|
98
92
|
* Add a passkey to the already-signed-in account (bearer present). Does NOT
|
|
99
93
|
* commit a new session; refreshes the linked auth-methods list on success.
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Extracted from `OxyContext` so the fixed `options → ceremony → verify → commit`
|
|
5
5
|
* ordering is unit-testable with injected deps — the exact pattern
|
|
6
6
|
* `commitSessionFlow.ts` (`commitDeviceSetAndResolve`) uses. The context methods
|
|
7
|
-
* (`signInWithPasskey` / `
|
|
7
|
+
* (`signInWithPasskey` / `addPasskey`) are thin wrappers
|
|
8
8
|
* that supply the real deps: the core `webauthn*` methods, the platform ceremony
|
|
9
9
|
* client (`webauthn/passkeyClient`), and the internal `commitSession` funnel.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Both GATE on `isSupported()` first (the platform client returns `false`
|
|
12
12
|
* off the web) so an unsupported surface fails loudly before touching a ceremony.
|
|
13
13
|
*/
|
|
14
14
|
|
|
@@ -84,43 +84,6 @@ export async function runPasskeyLogin(deps: RunPasskeyLoginDeps): Promise<void>
|
|
|
84
84
|
await deps.commit(toCommitInput(result));
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/** Injected dependencies for {@link runPasskeyRegister}. */
|
|
88
|
-
export interface RunPasskeyRegisterDeps {
|
|
89
|
-
isSupported: () => boolean;
|
|
90
|
-
getRegisterOptions: (username: string) => Promise<unknown>;
|
|
91
|
-
runCeremony: (optionsJSON: unknown) => Promise<unknown>;
|
|
92
|
-
registerVerify: (
|
|
93
|
-
response: unknown,
|
|
94
|
-
envelope: { username: string; deviceName?: string },
|
|
95
|
-
) => Promise<PasskeyRegisterVerifyResult>;
|
|
96
|
-
commit: (input: CommitInput) => Promise<void>;
|
|
97
|
-
username: string;
|
|
98
|
-
deviceName?: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Passkey SIGNUP: create a brand-new account whose first auth method is a
|
|
103
|
-
* passkey. The verify signup branch mints a session (a {@link LoginSessionResult}
|
|
104
|
-
* carrying `sessionId`), which is committed exactly like a password signup.
|
|
105
|
-
*/
|
|
106
|
-
export async function runPasskeyRegister(deps: RunPasskeyRegisterDeps): Promise<void> {
|
|
107
|
-
if (!deps.isSupported()) {
|
|
108
|
-
throw new Error(PASSKEY_UNSUPPORTED_MESSAGE);
|
|
109
|
-
}
|
|
110
|
-
const options = await deps.getRegisterOptions(deps.username);
|
|
111
|
-
const response = await deps.runCeremony(options);
|
|
112
|
-
const result = await deps.registerVerify(response, {
|
|
113
|
-
username: deps.username,
|
|
114
|
-
deviceName: deps.deviceName,
|
|
115
|
-
});
|
|
116
|
-
// Only the signup session arm carries `sessionId`; the link branch
|
|
117
|
-
// (`{ success, message }`) does not.
|
|
118
|
-
if (!('sessionId' in result)) {
|
|
119
|
-
throw new Error('Passkey registration did not establish a session.');
|
|
120
|
-
}
|
|
121
|
-
await deps.commit(toCommitInput(result));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
87
|
/** Injected dependencies for {@link runPasskeyAdd}. */
|
|
125
88
|
export interface RunPasskeyAddDeps {
|
|
126
89
|
isSupported: () => boolean;
|
|
@@ -11,7 +11,7 @@ import { H4, Text } from '@oxy.so/bloom/typography';
|
|
|
11
11
|
import { Button } from '@oxy.so/bloom/button';
|
|
12
12
|
import { TextField, TextFieldInput } from '@oxy.so/bloom/text-field';
|
|
13
13
|
import { IconCircle } from '@oxy.so/bloom/icon-circle';
|
|
14
|
-
import { BenefitList, BenefitRow } from '
|
|
14
|
+
import { BenefitList, BenefitRow } from '../components/BenefitList';
|
|
15
15
|
import * as Icons from '@oxy.so/bloom/icons';
|
|
16
16
|
import { useI18n } from '../hooks/useI18n';
|
|
17
17
|
import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
|
|
@@ -82,7 +82,7 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
|
|
|
82
82
|
<View className="px-screen-margin pb-space-32">
|
|
83
83
|
{/* Hero */}
|
|
84
84
|
<View className="items-center py-space-24 gap-space-12">
|
|
85
|
-
<IconCircle icon={Icons.
|
|
85
|
+
<IconCircle icon={Icons.RiVerifiedBadgeLine} />
|
|
86
86
|
<H4 className="text-headerBold font-headerBold text-text text-center">
|
|
87
87
|
{t('accountVerification.heroTitle') || 'Get a verified badge'}
|
|
88
88
|
</H4>
|
|
@@ -97,15 +97,15 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
|
|
|
97
97
|
accessibilityLabel={t('accountVerification.sections.benefits') || 'What verification gives you'}
|
|
98
98
|
>
|
|
99
99
|
<BenefitRow
|
|
100
|
-
icon={<Icons.
|
|
100
|
+
icon={<Icons.RiShieldCheckLine size="sm" style={{ color: bloomTheme.colors.primary }} />}
|
|
101
101
|
label={t('accountVerification.benefits.authenticity') || 'Confirms your identity is authentic and trusted'}
|
|
102
102
|
/>
|
|
103
103
|
<BenefitRow
|
|
104
|
-
icon={<Icons.
|
|
104
|
+
icon={<Icons.RiVerifiedBadgeLine size="sm" style={{ color: bloomTheme.colors.primary }} />}
|
|
105
105
|
label={t('accountVerification.benefits.badge') || 'Displays a verified badge across the platform'}
|
|
106
106
|
/>
|
|
107
107
|
<BenefitRow
|
|
108
|
-
icon={<Icons.
|
|
108
|
+
icon={<Icons.RiSparklingLine size="sm" style={{ color: bloomTheme.colors.primary }} />}
|
|
109
109
|
label={t('accountVerification.benefits.credibility') || 'Builds credibility with people who follow you'}
|
|
110
110
|
/>
|
|
111
111
|
</BenefitList>
|
|
@@ -161,7 +161,7 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
|
|
|
161
161
|
</Button>
|
|
162
162
|
|
|
163
163
|
<View className="flex-row items-start gap-space-8 mt-space-24">
|
|
164
|
-
<Icons.
|
|
164
|
+
<Icons.RiInformationLine
|
|
165
165
|
size="sm"
|
|
166
166
|
style={{ color: bloomTheme.colors.textTertiary }}
|
|
167
167
|
/>
|
|
@@ -28,31 +28,31 @@ const INFO_SECTIONS: InfoSection[] = [
|
|
|
28
28
|
id: 'what',
|
|
29
29
|
titleKey: 'learnMoreUsernames.sections.what.title',
|
|
30
30
|
contentKey: 'learnMoreUsernames.sections.what.content',
|
|
31
|
-
Icon: Icons.
|
|
31
|
+
Icon: Icons.RiAtLine,
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
id: 'rules',
|
|
35
35
|
titleKey: 'learnMoreUsernames.sections.rules.title',
|
|
36
36
|
contentKey: 'learnMoreUsernames.sections.rules.content',
|
|
37
|
-
Icon: Icons.
|
|
37
|
+
Icon: Icons.RiListUnordered,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
id: 'unique',
|
|
41
41
|
titleKey: 'learnMoreUsernames.sections.unique.title',
|
|
42
42
|
contentKey: 'learnMoreUsernames.sections.unique.content',
|
|
43
|
-
Icon: Icons.
|
|
43
|
+
Icon: Icons.RiKey2Line,
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
id: 'change',
|
|
47
47
|
titleKey: 'learnMoreUsernames.sections.change.title',
|
|
48
48
|
contentKey: 'learnMoreUsernames.sections.change.content',
|
|
49
|
-
Icon: Icons.
|
|
49
|
+
Icon: Icons.RiResetRightLine,
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
id: 'tips',
|
|
53
53
|
titleKey: 'learnMoreUsernames.sections.tips.title',
|
|
54
54
|
contentKey: 'learnMoreUsernames.sections.tips.content',
|
|
55
|
-
Icon: Icons.
|
|
55
|
+
Icon: Icons.RiSparklingLine,
|
|
56
56
|
},
|
|
57
57
|
];
|
|
58
58
|
|
|
@@ -84,7 +84,7 @@ const LearnMoreUsernamesScreen: React.FC<BaseScreenProps> = ({
|
|
|
84
84
|
<>
|
|
85
85
|
<View className="px-screen-margin pb-space-32">
|
|
86
86
|
<View className="items-center py-space-24 gap-space-12">
|
|
87
|
-
<IconCircle icon={Icons.
|
|
87
|
+
<IconCircle icon={Icons.RiAtLine} />
|
|
88
88
|
<Text className="font-sans text-body text-text-secondary text-center">
|
|
89
89
|
{t('learnMoreUsernames.introText')}
|
|
90
90
|
</Text>
|
|
@@ -10,7 +10,7 @@ import { Chip } from '@oxy.so/bloom/chip';
|
|
|
10
10
|
import { Badge } from '@oxy.so/bloom/badge';
|
|
11
11
|
import { Card, CardBody } from '@oxy.so/bloom/card';
|
|
12
12
|
import { H2, H4, H5, Text } from '@oxy.so/bloom/typography';
|
|
13
|
-
import { BenefitList, BenefitRow } from '
|
|
13
|
+
import { BenefitList, BenefitRow } from '../components/BenefitList';
|
|
14
14
|
import {
|
|
15
15
|
SegmentedControl,
|
|
16
16
|
SegmentedControlItem,
|
|
@@ -3,7 +3,7 @@ import { View } from 'react-native';
|
|
|
3
3
|
import { useTheme } from '@oxy.so/bloom/theme';
|
|
4
4
|
import { H4, Text } from '@oxy.so/bloom/typography';
|
|
5
5
|
import { IconCircle } from '@oxy.so/bloom/icon-circle';
|
|
6
|
-
import { BenefitList, BenefitRow } from '
|
|
6
|
+
import { BenefitList, BenefitRow } from '../../components/BenefitList';
|
|
7
7
|
import * as Icons from '@oxy.so/bloom/icons';
|
|
8
8
|
import type { BaseScreenProps } from '../../types/navigation';
|
|
9
9
|
import { useI18n } from '../../hooks/useI18n';
|
|
@@ -22,7 +22,7 @@ const TrustAboutScreen: React.FC<BaseScreenProps> = () => {
|
|
|
22
22
|
return (
|
|
23
23
|
<View className="px-screen-margin pt-space-16 pb-space-32">
|
|
24
24
|
<View className="items-center py-space-24 gap-space-12">
|
|
25
|
-
<IconCircle icon={Icons.
|
|
25
|
+
<IconCircle icon={Icons.RiShieldCheckLine} />
|
|
26
26
|
<Text className="font-sans text-body text-text-secondary text-center">
|
|
27
27
|
{t('trust.about.intro') || 'Oxy Trust is a recognition of your positive actions in the Oxy Ecosystem. Reputation cannot be sent or received directly, only earned by contributing to the community.'}
|
|
28
28
|
</Text>
|
|
@@ -36,23 +36,23 @@ const TrustAboutScreen: React.FC<BaseScreenProps> = () => {
|
|
|
36
36
|
accessibilityLabel={t('trust.about.how.title') || 'How to Earn Reputation'}
|
|
37
37
|
>
|
|
38
38
|
<BenefitRow
|
|
39
|
-
icon={<Icons.
|
|
39
|
+
icon={<Icons.RiAccountCircleLine size="sm" style={{ color: iconColor }} />}
|
|
40
40
|
label={t('trust.about.how.help') || 'Helping other users'}
|
|
41
41
|
/>
|
|
42
42
|
<BenefitRow
|
|
43
|
-
icon={<Icons.
|
|
43
|
+
icon={<Icons.RiFlagLine size="sm" style={{ color: iconColor }} />}
|
|
44
44
|
label={t('trust.about.how.report') || 'Reporting bugs'}
|
|
45
45
|
/>
|
|
46
46
|
<BenefitRow
|
|
47
|
-
icon={<Icons.
|
|
47
|
+
icon={<Icons.RiEditLine size="sm" style={{ color: iconColor }} />}
|
|
48
48
|
label={t('trust.about.how.contribute') || 'Contributing content'}
|
|
49
49
|
/>
|
|
50
50
|
<BenefitRow
|
|
51
|
-
icon={<Icons.
|
|
51
|
+
icon={<Icons.RiCalendarLine size="sm" style={{ color: iconColor }} />}
|
|
52
52
|
label={t('trust.about.how.participate') || 'Participating in events'}
|
|
53
53
|
/>
|
|
54
54
|
<BenefitRow
|
|
55
|
-
icon={<Icons.
|
|
55
|
+
icon={<Icons.RiSparklingLine size="sm" style={{ color: iconColor }} />}
|
|
56
56
|
label={t('trust.about.how.other') || 'Other positive actions'}
|
|
57
57
|
/>
|
|
58
58
|
</BenefitList>
|