@opexa/portal-components 0.0.1045 → 0.0.1047

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.
@@ -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 ||
@@ -50,6 +50,7 @@ export function MobileNumberSignIn() {
50
50
  kyc: ctx.kyc,
51
51
  registerBiometrics: ctx.registerBiometrics,
52
52
  disclaimer: ctx.disclaimer,
53
+ termsOfUse: ctx.termsOfUse,
53
54
  })));
54
55
  const signInMutation = useSignInMutation({
55
56
  onSuccess: async () => {
@@ -229,7 +230,7 @@ export function MobileNumberSignIn() {
229
230
  router.push(signInProps.termsAndConditionsUrl);
230
231
  }
231
232
  else {
232
- globalStore.termsAndConditions.setOpen(true);
233
+ globalStore.termsOfUse.setOpen(true);
233
234
  globalStore.termsAndConditions.setNext('SIGN_IN');
234
235
  }
235
236
  }, children: "Terms of Use" }), ' ', "and", ' ', _jsx("button", { type: "button", className: "text-brand-400 underline underline-offset-2", onClick: () => {
@@ -51,6 +51,7 @@ export function NameAndPasswordSignIn() {
51
51
  responsibleGamingReminder: ctx.responsibleGamingReminder,
52
52
  registerBiometrics: ctx.registerBiometrics,
53
53
  disclaimer: ctx.disclaimer,
54
+ termsOfUse: ctx.termsOfUse,
54
55
  })));
55
56
  const [formType, setFormType] = useState('NAME_AND_PASSWORD');
56
57
  const signInMutation = useSignInMutation({
@@ -312,7 +313,7 @@ export function NameAndPasswordSignIn() {
312
313
  router.push(signInProps.termsAndConditionsUrl);
313
314
  }
314
315
  else {
315
- globalStore.termsAndConditions.setOpen(true);
316
+ globalStore.termsOfUse.setOpen(true);
316
317
  globalStore.termsAndConditions.setNext('SIGN_IN');
317
318
  }
318
319
  }, children: "Terms of Use" }), ' ', "and", ' ', _jsx("button", { type: "button", className: "text-brand-400 underline underline-offset-2", onClick: () => {
@@ -60,6 +60,7 @@ export function SignUpDefaultForm() {
60
60
  termsAndConditions: ctx.termsAndConditions,
61
61
  responsibleGaming: ctx.responsibleGaming,
62
62
  kyc: ctx.kyc,
63
+ termsOfUse: ctx.termsOfUse,
63
64
  })));
64
65
  const search = useSearchParams();
65
66
  const signUpMutation = useSignUpMutation();
@@ -90,9 +91,7 @@ export function SignUpDefaultForm() {
90
91
  .refine((val) => val.length <= 50, {
91
92
  message: 'Last name must not be more than 50 characters',
92
93
  });
93
- const birthdateBaseSchema = z
94
- .custom()
95
- .superRefine((val, ctx) => {
94
+ const birthdateBaseSchema = z.custom().superRefine((val, ctx) => {
96
95
  if (!(val instanceof Date)) {
97
96
  ctx.addIssue({
98
97
  code: z.ZodIssueCode.custom,
@@ -272,7 +271,7 @@ export function SignUpDefaultForm() {
272
271
  router.push(signUpProps.termsAndConditionsUrl);
273
272
  }
274
273
  else {
275
- globalStore.termsAndConditions.setOpen(true);
274
+ globalStore.termsOfUse.setOpen(true);
276
275
  globalStore.termsAndConditions.setNext('SIGN_UP');
277
276
  }
278
277
  }, children: "Terms and Conditions" }), ' ', "and", ' ', _jsx("button", { type: "button", className: "text-brand-400 underline underline-offset-2", onClick: () => {
@@ -303,7 +302,8 @@ export function SignUpDefaultForm() {
303
302
  }),
304
303
  ...(signUpProps?.branches &&
305
304
  signUpProps.branches.length > 0 && {
306
- branchCode: signUpProps.branches.find((b) => itemToValue(b) === step1Form.getValues('branchCode'))?.code ?? step1Form.getValues('branchCode'),
305
+ branchCode: signUpProps.branches.find((b) => itemToValue(b) ===
306
+ step1Form.getValues('branchCode'))?.code ?? step1Form.getValues('branchCode'),
307
307
  }),
308
308
  }),
309
309
  ...(signUpProps.showEmailAddressField && {
@@ -55,6 +55,7 @@ export function SignUpNameAndPasswordForm() {
55
55
  termsAndConditions: ctx.termsAndConditions,
56
56
  responsibleGaming: ctx.responsibleGaming,
57
57
  kyc: ctx.kyc,
58
+ termsOfUse: ctx.termsOfUse,
58
59
  })));
59
60
  const definition = z.object({
60
61
  name: z
@@ -211,7 +212,7 @@ export function SignUpNameAndPasswordForm() {
211
212
  router.push(signUpProps.termsAndConditionsUrl);
212
213
  }
213
214
  else {
214
- globalStore.termsAndConditions.setOpen(true);
215
+ globalStore.termsOfUse.setOpen(true);
215
216
  globalStore.termsAndConditions.setNext('SIGN_UP');
216
217
  globalStore.signUp.setOpen(false);
217
218
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.1045",
3
+ "version": "0.0.1047",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",