@opexa/portal-components 0.0.1046 → 0.0.1048

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.
@@ -155,6 +155,9 @@ export function Withdrawal() {
155
155
  allowUnverifiedAccounts) {
156
156
  return _jsx(AccountVerificationRequired, {});
157
157
  }
158
+ if (memberVerification.status === 'PENDING') {
159
+ return _jsx(_AccountVerificationPending, {});
160
+ }
158
161
  if (enabledPaymentMethods.length <= 0) {
159
162
  return _jsx(NoAvailablePaymentMethods, {});
160
163
  }
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createListCollection } from '@ark-ui/react';
2
3
  import { Capacitor } from '@capacitor/core';
3
4
  import { zodResolver } from '@hookform/resolvers/zod';
4
5
  import { useRouter } from 'next/navigation';
5
- import { useForm } from 'react-hook-form';
6
+ import { Controller, useForm } from 'react-hook-form';
6
7
  import { twMerge } from 'tailwind-merge';
7
8
  import invariant from 'tiny-invariant';
8
9
  import { z } from 'zod';
@@ -18,21 +19,75 @@ import { getSession } from '../../../client/services/getSession.js';
18
19
  import { BIOMETRIC_STORAGE_KEY } from '../../../client/utils/biometric.js';
19
20
  import { toaster } from '../../../client/utils/toaster.js';
20
21
  import { CheckIcon } from '../../../icons/CheckIcon.js';
22
+ import { ChevronDownIcon } from '../../../icons/ChevronDownIcon.js';
21
23
  import { unregisterFCMDevice } from '../../../services/trigger.js';
22
24
  import { Button } from '../../../ui/Button/index.js';
23
25
  import { Checkbox } from '../../../ui/Checkbox/index.js';
24
26
  import { Dialog } from '../../../ui/Dialog/index.js';
25
27
  import { Field } from '../../../ui/Field/index.js';
28
+ import { Select } from '../../../ui/Select/index.js';
26
29
  import { getQueryClient } from '../../../utils/getQueryClient.js';
27
30
  import { getAccountQueryKey, getMemberVerificationQueryKey, getSessionQueryKey, } from '../../../utils/queryKeys.js';
28
31
  import { useKYCDefaultContext } from './KYCDefaultContext.js';
29
- const definition = z.object({
32
+ const SOURCE_OF_INCOME_OPTIONS = [
33
+ { label: 'Salary', value: 'Salary' },
34
+ { label: 'Business / Self Employment', value: 'Business / Self Employment' },
35
+ { label: 'Pension', value: 'Pension' },
36
+ { label: 'Others', value: 'Others' },
37
+ ];
38
+ const sourceOfIncomeCollection = createListCollection({
39
+ items: SOURCE_OF_INCOME_OPTIONS,
40
+ itemToValue: (item) => item.value,
41
+ itemToString: (item) => item.label,
42
+ });
43
+ const NATURE_OF_WORK_OPTIONS = [
44
+ { label: 'Administrative', value: 'Administrative' },
45
+ { label: 'Creative', value: 'Creative' },
46
+ { label: 'Customer Service', value: 'Customer Service' },
47
+ { label: 'Technical', value: 'Technical' },
48
+ { label: 'Management', value: 'Management' },
49
+ { label: 'Research', value: 'Research' },
50
+ { label: 'Sales', value: 'Sales' },
51
+ { label: 'Support', value: 'Support' },
52
+ { label: 'Operations', value: 'Operations' },
53
+ { label: 'Teaching', value: 'Teaching' },
54
+ { label: 'Others', value: 'Others' },
55
+ ];
56
+ const natureOfWorkCollection = createListCollection({
57
+ items: NATURE_OF_WORK_OPTIONS,
58
+ itemToValue: (item) => item.value,
59
+ itemToString: (item) => item.label,
60
+ });
61
+ const definition = z
62
+ .object({
30
63
  address: z.string().trim().min(1, 'Current address is required'),
31
64
  permanentAddress: z.string().trim().min(1, 'Permanent address is required'),
32
- sourceOfIncome: z.string().trim().min(1, 'Source of Income is required'),
33
- natureOfWork: z.string().trim().min(1, 'Nature of Work is required'),
65
+ sourceOfIncome: z.string().min(1, 'Source of Income is required'),
66
+ sourceOfIncomeOther: z.string().optional(),
67
+ natureOfWork: z.string().min(1, 'Nature of Work is required'),
68
+ natureOfWorkOther: z.string().optional(),
34
69
  placeOfBirth: z.string().trim().min(1, 'Place of Birth is required'),
35
70
  nationality: z.string().trim().min(1, 'Nationality is required'),
71
+ })
72
+ .superRefine((data, ctx) => {
73
+ if (data.sourceOfIncome === 'Others') {
74
+ if (!data.sourceOfIncomeOther?.trim()) {
75
+ ctx.addIssue({
76
+ code: z.ZodIssueCode.custom,
77
+ message: 'Please specify your source of income',
78
+ path: ['sourceOfIncomeOther'],
79
+ });
80
+ }
81
+ }
82
+ if (data.natureOfWork === 'Others') {
83
+ if (!data.natureOfWorkOther?.trim()) {
84
+ ctx.addIssue({
85
+ code: z.ZodIssueCode.custom,
86
+ message: 'Please specify your nature of work',
87
+ path: ['natureOfWorkOther'],
88
+ });
89
+ }
90
+ }
36
91
  });
37
92
  export function PersonalInformation() {
38
93
  const kyc = useKYCDefaultContext();
@@ -123,24 +178,37 @@ export function PersonalInformation() {
123
178
  defaultValues: {
124
179
  address: '',
125
180
  nationality: '',
126
- natureOfWork: '',
127
181
  placeOfBirth: '',
128
182
  permanentAddress: '',
183
+ sourceOfIncome: '',
184
+ sourceOfIncomeOther: '',
185
+ natureOfWork: '',
186
+ natureOfWorkOther: '',
129
187
  },
130
188
  mode: 'all',
131
189
  });
132
190
  async function onSubmit(values) {
191
+ const resolvedSourceOfIncome = values.sourceOfIncome === 'Others'
192
+ ? (values.sourceOfIncomeOther ?? '').trim()
193
+ : values.sourceOfIncome;
194
+ const resolvedNatureOfWork = values.natureOfWork === 'Others'
195
+ ? (values.natureOfWorkOther ?? '').trim()
196
+ : values.natureOfWork;
197
+ const payload = {
198
+ address: values.address,
199
+ permanentAddress: values.permanentAddress,
200
+ sourceOfIncome: resolvedSourceOfIncome,
201
+ natureOfWork: resolvedNatureOfWork,
202
+ placeOfBirth: values.placeOfBirth,
203
+ nationality: values.nationality,
204
+ };
133
205
  if (!memberVerificationId) {
134
- createMemberVerificationMutation.mutate({
135
- ...values,
136
- });
206
+ createMemberVerificationMutation.mutate(payload);
137
207
  }
138
208
  else {
139
209
  await updateMemberVerificationMutation.mutateAsync({
140
210
  id: memberVerificationId,
141
- data: {
142
- ...values,
143
- },
211
+ data: payload,
144
212
  });
145
213
  await approveMemberVerificationMutation.mutateAsync(memberVerificationId);
146
214
  }
@@ -166,7 +234,25 @@ export function PersonalInformation() {
166
234
  address: '',
167
235
  });
168
236
  }
169
- }, disabled: !permanentAddress, children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsx(Checkbox.Label, { children: "Use permanent address as current address" }), _jsx(Checkbox.HiddenInput, {})] }), _jsxs(Field.Root, { className: "mt-2xl", invalid: !!form.formState.errors.sourceOfIncome, children: [_jsx(Field.Label, { children: "Source of income" }), _jsx(Field.Input, { placeholder: "Enter your source of income", ...form.register('sourceOfIncome') }), _jsx(Field.ErrorText, { children: form.formState.errors.sourceOfIncome?.message })] }), _jsxs(Field.Root, { className: "mt-2xl", invalid: !!form.formState.errors.natureOfWork, children: [_jsx(Field.Label, { children: "Nature of Work" }), _jsx(Field.Input, { placeholder: "Enter your nature of work", ...form.register('natureOfWork') }), _jsx(Field.ErrorText, { children: form.formState.errors.natureOfWork?.message })] }), _jsxs(Field.Root, { className: "mt-2xl", invalid: !!form.formState.errors.placeOfBirth, children: [_jsx(Field.Label, { children: "Place of birth" }), _jsx(Field.Input, { placeholder: "Enter your place of birth", ...form.register('placeOfBirth') }), _jsx(Field.ErrorText, { children: form.formState.errors.placeOfBirth?.message })] }), _jsxs(Field.Root, { className: "mt-2xl", invalid: !!form.formState.errors.nationality, children: [_jsx(Field.Label, { children: "Nationality" }), _jsx(Field.Input, { placeholder: "Enter your nationality", ...form.register('nationality') }), _jsx(Field.ErrorText, { children: form.formState.errors.nationality?.message })] }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: updateMemberVerificationMutation.isPending ||
237
+ }, disabled: !permanentAddress, children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsx(Checkbox.Label, { children: "Use permanent address as current address" }), _jsx(Checkbox.HiddenInput, {})] }), _jsx(Controller, { control: form.control, name: "sourceOfIncome", render: ({ field, fieldState }) => (_jsxs(Field.Root, { className: "mt-2xl", invalid: fieldState.invalid, children: [_jsx(Field.Label, { children: "Source of income" }), _jsxs(Select.Root, { collection: sourceOfIncomeCollection, value: field.value ? [field.value] : [], onValueChange: (details) => {
238
+ const selected = details.value?.[0] ?? '';
239
+ field.onChange(selected);
240
+ if (selected !== 'others') {
241
+ form.setValue('sourceOfIncomeOther', '', {
242
+ shouldDirty: true,
243
+ shouldValidate: true,
244
+ });
245
+ }
246
+ }, positioning: { sameWidth: true, placement: 'bottom' }, lazyMount: true, unmountOnExit: true, children: [_jsxs(Select.Trigger, { children: [_jsx(Select.ValueText, { placeholder: "Select source of income" }), _jsx(Select.Indicator, { asChild: true, children: _jsx(ChevronDownIcon, {}) })] }), _jsx(Select.Positioner, { children: _jsx(Select.Content, { children: SOURCE_OF_INCOME_OPTIONS.map((option) => (_jsx(Select.Item, { item: option, children: _jsx(Select.ItemText, { children: option.label }) }, option.value))) }) })] }), _jsx(Field.ErrorText, { children: fieldState.error?.message })] })) }), form.watch('sourceOfIncome') === 'Others' && (_jsxs(Field.Root, { className: "mt-xl", invalid: !!form.formState.errors.sourceOfIncomeOther, children: [_jsx(Field.Label, { children: "Please specify your source of income" }), _jsx(Field.Input, { placeholder: "Please specify your source of income", ...form.register('sourceOfIncomeOther') }), _jsx(Field.ErrorText, { children: form.formState.errors.sourceOfIncomeOther?.message })] })), _jsx(Controller, { control: form.control, name: "natureOfWork", render: ({ field, fieldState }) => (_jsxs(Field.Root, { className: "mt-2xl", invalid: fieldState.invalid, children: [_jsx(Field.Label, { children: "Nature of Work" }), _jsxs(Select.Root, { collection: natureOfWorkCollection, value: field.value ? [field.value] : [], onValueChange: (details) => {
247
+ const selected = details.value?.[0] ?? '';
248
+ field.onChange(selected);
249
+ if (selected !== 'Others') {
250
+ form.setValue('natureOfWorkOther', '', {
251
+ shouldDirty: true,
252
+ shouldValidate: true,
253
+ });
254
+ }
255
+ }, positioning: { sameWidth: true, placement: 'bottom' }, lazyMount: true, unmountOnExit: true, children: [_jsxs(Select.Trigger, { children: [_jsx(Select.ValueText, { placeholder: "Select nature of work" }), _jsx(Select.Indicator, { asChild: true, children: _jsx(ChevronDownIcon, {}) })] }), _jsx(Select.Positioner, { children: _jsx(Select.Content, { children: NATURE_OF_WORK_OPTIONS.map((option) => (_jsx(Select.Item, { item: option, children: _jsx(Select.ItemText, { children: option.label }) }, option.value))) }) })] }), _jsx(Field.ErrorText, { children: fieldState.error?.message })] })) }), form.watch('natureOfWork') === 'Others' && (_jsxs(Field.Root, { className: "mt-xl", invalid: !!form.formState.errors.natureOfWorkOther, children: [_jsx(Field.Label, { children: "Please specify your nature of work" }), _jsx(Field.Input, { placeholder: "Please specify your nature of work", ...form.register('natureOfWorkOther') }), _jsx(Field.ErrorText, { children: form.formState.errors.natureOfWorkOther?.message })] })), _jsxs(Field.Root, { className: "mt-2xl", invalid: !!form.formState.errors.placeOfBirth, children: [_jsx(Field.Label, { children: "Place of birth" }), _jsx(Field.Input, { placeholder: "Enter your place of birth", ...form.register('placeOfBirth') }), _jsx(Field.ErrorText, { children: form.formState.errors.placeOfBirth?.message })] }), _jsxs(Field.Root, { className: "mt-2xl", invalid: !!form.formState.errors.nationality, children: [_jsx(Field.Label, { children: "Nationality" }), _jsx(Field.Input, { placeholder: "Enter your nationality", ...form.register('nationality') }), _jsx(Field.ErrorText, { children: form.formState.errors.nationality?.message })] }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: updateMemberVerificationMutation.isPending ||
170
256
  createMemberVerificationMutation.isPending, children: "Continue" }), kyc.isSkippable && (_jsx(Button, { variant: "outline", colorScheme: "gray", className: twMerge('mt-lg', accountStatus === 'VERIFICATION_LOCKED' && 'hidden'), type: "button", onClick: () => {
171
257
  globalStore.kyc.setOpen(false);
172
258
  }, disabled: updateMemberVerificationMutation.isPending ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.1046",
3
+ "version": "0.0.1048",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",