@swan-io/shared-business 1.1.0 → 1.2.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/package.json +6 -2
- package/src/components/AddressFormPart.d.ts +21 -0
- package/src/components/AddressFormPart.js +26 -0
- package/src/components/AddressSearchInput.d.ts +8 -12
- package/src/components/AddressSearchInput.js +99 -16
- package/src/components/BeneficiaryForm.d.ts +39 -0
- package/src/components/BeneficiaryForm.js +282 -0
- package/src/components/LakeCityInput.d.ts +20 -0
- package/src/components/LakeCityInput.js +86 -0
- package/src/components/SupportingDocument.d.ts +1 -1
- package/src/components/SupportingDocument.js +8 -8
- package/src/components/UploadArea.js +5 -5
- package/src/constants/countries.d.ts +5 -5
- package/src/constants/countries.js +2 -0
- package/src/hooks/useGoogleMapSDK.d.ts +8 -0
- package/src/hooks/useGoogleMapSDK.js +22 -0
- package/src/utils/i18n.d.ts +3 -3
- package/README.md +0 -1
- package/src/third-party/Pappers.d.ts +0 -8
- package/src/third-party/Pappers.js +0 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swan-io/shared-business",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=14.0.0",
|
|
6
6
|
"yarn": "^1.20.0"
|
|
@@ -22,11 +22,14 @@
|
|
|
22
22
|
"not ie <= 11",
|
|
23
23
|
"safari >= 12"
|
|
24
24
|
],
|
|
25
|
+
"license": "MIT",
|
|
25
26
|
"dependencies": {
|
|
26
27
|
"@formatjs/intl": "2.6.7",
|
|
28
|
+
"@googlemaps/js-api-loader": "1.15.1",
|
|
27
29
|
"@swan-io/boxed": "0.12.1",
|
|
28
|
-
"@swan-io/lake": "
|
|
30
|
+
"@swan-io/lake": "*",
|
|
29
31
|
"react": "18.2.0",
|
|
32
|
+
"react-atomic-state": "1.2.7",
|
|
30
33
|
"react-dom": "18.2.0",
|
|
31
34
|
"react-native-web": "0.18.12",
|
|
32
35
|
"react-ux-form": "1.3.0",
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
"devDependencies": {
|
|
36
39
|
"@testing-library/react": "13.4.0",
|
|
37
40
|
"@testing-library/user-event": "14.4.3",
|
|
41
|
+
"@types/google.maps": "3.52.2",
|
|
38
42
|
"@types/react": "18.0.28",
|
|
39
43
|
"@types/react-dom": "18.0.11",
|
|
40
44
|
"@types/react-native": "0.70.11",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CountryCCA3 } from "@swan-io/shared-business/src/constants/countries";
|
|
3
|
+
import { useForm } from "react-ux-form";
|
|
4
|
+
type AddressField = {
|
|
5
|
+
address: string;
|
|
6
|
+
city: string;
|
|
7
|
+
postalCode: string;
|
|
8
|
+
};
|
|
9
|
+
type FormProps = Pick<ReturnType<typeof useForm<AddressField>>, "Field" | "setFieldValue" | "listenFields">;
|
|
10
|
+
type Props = {
|
|
11
|
+
initialAddress: string;
|
|
12
|
+
initialCity: string;
|
|
13
|
+
initialPostalCode: string;
|
|
14
|
+
country: CountryCCA3;
|
|
15
|
+
label: string;
|
|
16
|
+
optionalLabel?: string;
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
isLarge: boolean;
|
|
19
|
+
} & FormProps;
|
|
20
|
+
export declare const AddressFormPart: ({ initialAddress, initialCity, initialPostalCode, country, label, optionalLabel, placeholder, Field, setFieldValue, listenFields, isLarge, }: Props) => JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AddressSearchInput } from "@swan-io/shared-business/src/components/AddressSearchInput";
|
|
3
|
+
import { LakeButton } from "@swan-io/lake/src/components/LakeButton";
|
|
4
|
+
import { LakeLabel } from "@swan-io/lake/src/components/LakeLabel";
|
|
5
|
+
import { LakeTextInput } from "@swan-io/lake/src/components/LakeTextInput";
|
|
6
|
+
import { Space } from "@swan-io/lake/src/components/Space";
|
|
7
|
+
import { useBoolean } from "@swan-io/lake/src/hooks/useBoolean";
|
|
8
|
+
import { useCallback, useEffect } from "react";
|
|
9
|
+
import { locale, t } from "../utils/i18n";
|
|
10
|
+
export const AddressFormPart = ({ initialAddress, initialCity, initialPostalCode, country, label, optionalLabel, placeholder, Field, setFieldValue, listenFields, isLarge, }) => {
|
|
11
|
+
const [manualModeEnabled, setManualMode] = useBoolean(initialAddress !== "" || initialCity !== "" || initialPostalCode !== "");
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!manualModeEnabled) {
|
|
14
|
+
return listenFields(["city", "postalCode"], () => {
|
|
15
|
+
setManualMode.on();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}, [manualModeEnabled, listenFields, setManualMode]);
|
|
19
|
+
const onSuggestion = useCallback((place) => {
|
|
20
|
+
setFieldValue("address", place.completeAddress);
|
|
21
|
+
setFieldValue("city", place.city);
|
|
22
|
+
setFieldValue("postalCode", place.postalCode);
|
|
23
|
+
setManualMode.on();
|
|
24
|
+
}, [setManualMode, setFieldValue]);
|
|
25
|
+
return (_jsxs(_Fragment, { children: [_jsx(Field, { name: "address", children: ({ ref, value, onChange, error }) => (_jsx(LakeLabel, { label: label ?? t("addressFormPart.addressLabel"), optionalLabel: optionalLabel, render: id => (_jsx(AddressSearchInput, { inputRef: ref, emptyResultText: t("common.noResult"), placeholder: placeholder ?? t("addressFormPart.placeholder"), language: locale.language, id: id, country: country, value: value, error: error, onValueChange: onChange, onSuggestion: onSuggestion })), actions: !manualModeEnabled && isLarge ? (_jsx(LakeButton, { mode: "secondary", size: "small", onPress: setManualMode.on, children: t("addressFormPart.setManual") })) : null })) }), !manualModeEnabled && !isLarge ? (_jsx(LakeButton, { mode: "secondary", size: "small", onPress: setManualMode.on, children: t("addressFormPart.setManual") })) : null, manualModeEnabled ? (_jsxs(_Fragment, { children: [_jsx(Space, { height: 12 }), _jsx(Field, { name: "city", children: ({ ref, value, valid, error, onChange }) => (_jsx(LakeLabel, { label: t("addressFormPart.cityLabel"), render: id => (_jsx(LakeTextInput, { ref: ref, nativeID: id, value: value, valid: valid, error: error, onChangeText: onChange })) })) }), _jsx(Space, { height: 12 }), _jsx(Field, { name: "postalCode", children: ({ ref, value, valid, error, onChange }) => (_jsx(LakeLabel, { label: t("addressFormPart.postCodeLabel"), render: id => (_jsx(LakeTextInput, { ref: ref, nativeID: id, value: value, valid: valid, error: error, onChangeText: onChange })) })) })] })) : null] }));
|
|
26
|
+
};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
import { CountryCCA3 } from "@swan-io/shared-business/src/constants/countries";
|
|
2
|
+
import { MutableRefObject } from "react";
|
|
3
3
|
import { StyleProp, ViewStyle } from "react-native";
|
|
4
|
-
type Suggestion = {
|
|
5
|
-
id: string;
|
|
6
|
-
firstLine: string;
|
|
7
|
-
secondLine: string;
|
|
8
|
-
};
|
|
9
4
|
export type PlaceDetail = {
|
|
10
5
|
completeAddress: string;
|
|
11
6
|
streetNumber: string;
|
|
@@ -14,19 +9,20 @@ export type PlaceDetail = {
|
|
|
14
9
|
postalCode: string;
|
|
15
10
|
};
|
|
16
11
|
type Props = {
|
|
12
|
+
inputRef?: MutableRefObject<unknown>;
|
|
17
13
|
id?: string;
|
|
18
14
|
country: CountryCCA3;
|
|
19
15
|
disabled?: boolean;
|
|
20
16
|
error?: string;
|
|
21
|
-
|
|
22
|
-
onSelectSuggestion: (suggestion: Suggestion) => Promise<PlaceDetail>;
|
|
17
|
+
onSuggestion?: (suggestion: PlaceDetail) => void;
|
|
23
18
|
onValueChange: (value: string) => void;
|
|
24
|
-
emptyResultText: string;
|
|
25
19
|
style?: StyleProp<ViewStyle>;
|
|
26
20
|
value?: string;
|
|
21
|
+
language: "en" | "es" | "de" | "fr" | "it" | "nl" | "pt";
|
|
27
22
|
placeholder: string;
|
|
28
23
|
shouldDisplaySuggestions?: boolean;
|
|
29
|
-
|
|
24
|
+
emptyResultText: string;
|
|
25
|
+
apiKey?: string;
|
|
30
26
|
};
|
|
31
|
-
export declare const AddressSearchInput: ({ id, country, disabled, error, value: initialValue, onValueChange,
|
|
27
|
+
export declare const AddressSearchInput: ({ inputRef, id, country, disabled, error, value: initialValue, onValueChange, onSuggestion, language, placeholder, shouldDisplaySuggestions, emptyResultText, apiKey, }: Props) => JSX.Element | null;
|
|
32
28
|
export {};
|
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { AsyncData, Future } from "@swan-io/boxed";
|
|
3
|
+
import { countriesWithMultipleCCA3, getCCA3forCCA2, } from "@swan-io/shared-business/src/constants/countries";
|
|
4
|
+
import { AutoWidthImage } from "@swan-io/lake/src/components/AutoWidthImage";
|
|
5
|
+
import { Box } from "@swan-io/lake/src/components/Box";
|
|
3
6
|
import { LakeCombobox } from "@swan-io/lake/src/components/LakeCombobox";
|
|
4
7
|
import { LakeTextInput } from "@swan-io/lake/src/components/LakeTextInput";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
+
import { colors } from "@swan-io/lake/src/constants/colors";
|
|
9
|
+
import { typography } from "@swan-io/lake/src/constants/typography";
|
|
10
|
+
import { useFirstMountState } from "@swan-io/lake/src/hooks/useFirstMountState";
|
|
11
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
12
|
+
import { StyleSheet, Text } from "react-native";
|
|
13
|
+
import { match } from "ts-pattern";
|
|
14
|
+
import poweredByGoogle from "../assets/images/powered_by_google_on_white_hdpi.png";
|
|
15
|
+
import { useGoogleMapSDK } from "../hooks/useGoogleMapSDK";
|
|
16
|
+
const styles = StyleSheet.create({
|
|
17
|
+
itemTitle: {
|
|
18
|
+
...typography.bodyLarge,
|
|
19
|
+
lineHeight: typography.lineHeights.title,
|
|
20
|
+
},
|
|
21
|
+
itemSubtitle: {
|
|
22
|
+
...typography.bodySmall,
|
|
23
|
+
color: colors.gray[50],
|
|
24
|
+
},
|
|
25
|
+
poweredByGoogle: {
|
|
26
|
+
paddingVertical: 8,
|
|
27
|
+
paddingHorizontal: 16,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
export const AddressSearchInput = ({ inputRef, id, country, disabled, error, value: initialValue, onValueChange, onSuggestion, language, placeholder, shouldDisplaySuggestions = true, emptyResultText, apiKey, }) => {
|
|
31
|
+
const isFirstMount = useFirstMountState();
|
|
8
32
|
const [state, setState] = useState(AsyncData.NotAsked());
|
|
9
33
|
const [value, setValue] = useState(initialValue ?? "");
|
|
10
34
|
const showTriggerSearchRef = useRef(true);
|
|
35
|
+
const sdk = useGoogleMapSDK({
|
|
36
|
+
language,
|
|
37
|
+
apiKey,
|
|
38
|
+
});
|
|
39
|
+
const autocomplete = useMemo(() => sdk.map(google => new google.maps.places.AutocompleteService()), [sdk]);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!isFirstMount && initialValue != null) {
|
|
42
|
+
setValue(initialValue);
|
|
43
|
+
}
|
|
44
|
+
}, [isFirstMount, initialValue]);
|
|
11
45
|
useEffect(() => {
|
|
12
46
|
if (value.length <= 3 || !shouldDisplaySuggestions || showTriggerSearchRef.current === false) {
|
|
13
47
|
return setState(AsyncData.NotAsked());
|
|
@@ -15,24 +49,73 @@ export const AddressSearchInput = ({ id, country, disabled, error, value: initia
|
|
|
15
49
|
setState(AsyncData.Loading());
|
|
16
50
|
const request = Future.make(resolve => {
|
|
17
51
|
const timeoutId = setTimeout(() => {
|
|
18
|
-
|
|
52
|
+
if (autocomplete.isDone()) {
|
|
53
|
+
Future.fromPromise(autocomplete.get().getPlacePredictions({
|
|
54
|
+
input: value,
|
|
55
|
+
componentRestrictions: { country: countriesWithMultipleCCA3[country] ?? [country] },
|
|
56
|
+
types: ["address"],
|
|
57
|
+
})).onResolve(resolve);
|
|
58
|
+
}
|
|
19
59
|
}, 250);
|
|
20
60
|
return () => clearTimeout(timeoutId);
|
|
21
|
-
});
|
|
61
|
+
}).mapOk(({ predictions }) => predictions.map(p => ({ value: p.place_id, prediction: p })), true);
|
|
22
62
|
request.onResolve(value => setState(AsyncData.Done(value)));
|
|
23
63
|
return () => request.cancel();
|
|
24
|
-
}, [country, value,
|
|
64
|
+
}, [country, value, autocomplete, shouldDisplaySuggestions]);
|
|
25
65
|
useEffect(() => {
|
|
26
66
|
showTriggerSearchRef.current = true;
|
|
27
67
|
}, [value]);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
68
|
+
return sdk.match({
|
|
69
|
+
NotAsked: () => null,
|
|
70
|
+
Loading: () => null,
|
|
71
|
+
Done: google => {
|
|
72
|
+
if (shouldDisplaySuggestions) {
|
|
73
|
+
const place = new google.maps.places.PlacesService(document.createElement("div"));
|
|
74
|
+
const selectAddress = (suggestion) => {
|
|
75
|
+
place.getDetails({ placeId: suggestion.value }, placeDetail => {
|
|
76
|
+
const result = {
|
|
77
|
+
completeAddress: "",
|
|
78
|
+
streetNumber: "",
|
|
79
|
+
postalCode: "",
|
|
80
|
+
country: "",
|
|
81
|
+
city: "",
|
|
82
|
+
};
|
|
83
|
+
placeDetail?.address_components?.forEach(({ types, short_name, long_name }) => {
|
|
84
|
+
const type = types[0];
|
|
85
|
+
match(type)
|
|
86
|
+
.with("street_number", () => (result.streetNumber = long_name))
|
|
87
|
+
.with("route", () => (result.completeAddress = long_name))
|
|
88
|
+
.with("postal_code", () => (result.postalCode = short_name))
|
|
89
|
+
.with("country", () => (result.country = getCCA3forCCA2(short_name) ?? short_name))
|
|
90
|
+
.with("locality", () => (result.city = long_name))
|
|
91
|
+
.otherwise(() => { });
|
|
92
|
+
});
|
|
93
|
+
if (result.streetNumber != "") {
|
|
94
|
+
if (placeDetail?.name === `${result.completeAddress} ${result.streetNumber}`) {
|
|
95
|
+
result.completeAddress = `${result.completeAddress} ${result.streetNumber}`;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
result.completeAddress = `${result.streetNumber} ${result.completeAddress}`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
showTriggerSearchRef.current = false;
|
|
102
|
+
setValue(result.completeAddress);
|
|
103
|
+
onSuggestion?.(result);
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
return (_jsx(LakeCombobox, { inputRef: inputRef, nativeID: id, placeholder: placeholder, value: value, items: state, icon: "search-filled", disabled: disabled, error: error, ListFooterComponent: _jsx(Box, { direction: "row", justifyContent: "end", style: styles.poweredByGoogle, children: _jsx(AutoWidthImage, { height: 14, sourceUri: poweredByGoogle }) }), onSelectItem: suggestion => selectAddress(suggestion), onValueChange: value => {
|
|
107
|
+
setValue(value);
|
|
108
|
+
onValueChange(value);
|
|
109
|
+
}, keyExtractor: item => item.value, emptyResultText: emptyResultText, renderItem: item => (_jsxs(_Fragment, { children: [_jsx(Text, { numberOfLines: 1, selectable: false, style: styles.itemTitle, children: item.prediction.structured_formatting.main_text }), _jsx(Text, { numberOfLines: 1, selectable: false, style: styles.itemSubtitle, children: item.prediction.structured_formatting.secondary_text })] })) }));
|
|
110
|
+
}
|
|
111
|
+
return (_jsx(LakeTextInput
|
|
112
|
+
// @ts-expect-error
|
|
113
|
+
, {
|
|
114
|
+
// @ts-expect-error
|
|
115
|
+
ref: inputRef, nativeID: id, placeholder: placeholder, value: value, icon: "search-filled", disabled: disabled, error: error, onChangeText: value => {
|
|
116
|
+
setValue(value);
|
|
117
|
+
onValueChange(value);
|
|
118
|
+
} }));
|
|
119
|
+
},
|
|
120
|
+
});
|
|
38
121
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CountryCCA3 } from "../constants/countries";
|
|
3
|
+
type BeneficiaryType = "HasCapital" | "LegalRepresentative" | "Other";
|
|
4
|
+
type AccountCountry = "DEU" | "ESP" | "FRA";
|
|
5
|
+
export type BeneficiaryFormStep = "common" | "address";
|
|
6
|
+
export type EditorState = {
|
|
7
|
+
reference: string;
|
|
8
|
+
firstName: string;
|
|
9
|
+
lastName: string;
|
|
10
|
+
birthDate: string;
|
|
11
|
+
birthCountryCode: CountryCCA3;
|
|
12
|
+
birthCity: string;
|
|
13
|
+
birthCityPostalCode: string;
|
|
14
|
+
type: BeneficiaryType;
|
|
15
|
+
indirect: boolean;
|
|
16
|
+
direct: boolean;
|
|
17
|
+
totalCapitalPercentage?: number;
|
|
18
|
+
residencyAddressLine1?: string;
|
|
19
|
+
residencyAddressCity?: string;
|
|
20
|
+
residencyAddressCountry?: string;
|
|
21
|
+
residencyAddressPostalCode?: string;
|
|
22
|
+
taxIdentificationNumber?: string;
|
|
23
|
+
};
|
|
24
|
+
type Props = {
|
|
25
|
+
initialState?: EditorState;
|
|
26
|
+
accountCountry: AccountCountry;
|
|
27
|
+
step: BeneficiaryFormStep;
|
|
28
|
+
onStepChange: (step: BeneficiaryFormStep) => void;
|
|
29
|
+
onSave: (editorState: EditorState) => void | Promise<void>;
|
|
30
|
+
onClose: () => void;
|
|
31
|
+
onCityLoadError: (error: unknown) => void;
|
|
32
|
+
};
|
|
33
|
+
export type BeneficiaryFormRef = {
|
|
34
|
+
cancel: () => void;
|
|
35
|
+
submit: () => void;
|
|
36
|
+
};
|
|
37
|
+
export declare const validateUbo: (editorState: EditorState, accountCountry: AccountCountry) => Partial<Record<keyof EditorState, string | undefined>>;
|
|
38
|
+
export declare const BeneficiaryForm: import("react").ForwardRefExoticComponent<Props & import("react").RefAttributes<BeneficiaryFormRef | undefined>>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from "@swan-io/lake/src/components/Box";
|
|
3
|
+
import { LakeLabelledCheckbox } from "@swan-io/lake/src/components/LakeCheckbox";
|
|
4
|
+
import { LakeLabel } from "@swan-io/lake/src/components/LakeLabel";
|
|
5
|
+
import { LakeText } from "@swan-io/lake/src/components/LakeText";
|
|
6
|
+
import { LakeTextInput } from "@swan-io/lake/src/components/LakeTextInput";
|
|
7
|
+
import { RadioGroup } from "@swan-io/lake/src/components/RadioGroup";
|
|
8
|
+
import { ResponsiveContainer } from "@swan-io/lake/src/components/ResponsiveContainer";
|
|
9
|
+
import { Space } from "@swan-io/lake/src/components/Space";
|
|
10
|
+
import { StepDots } from "@swan-io/lake/src/components/StepDots";
|
|
11
|
+
import { breakpoints, colors } from "@swan-io/lake/src/constants/design";
|
|
12
|
+
import { noop } from "@swan-io/lake/src/utils/function";
|
|
13
|
+
import { isNotNullish, isNotNullishOrEmpty } from "@swan-io/lake/src/utils/nullish";
|
|
14
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
15
|
+
import { StyleSheet, View } from "react-native";
|
|
16
|
+
import { hasDefinedKeys, useForm } from "react-ux-form";
|
|
17
|
+
import { Rifm } from "rifm";
|
|
18
|
+
import { match } from "ts-pattern";
|
|
19
|
+
import { v4 as uuid } from "uuid";
|
|
20
|
+
import { individualCountriesItems, isCountryCCA3 } from "../constants/countries";
|
|
21
|
+
import { decodeBirthDate, encodeBirthDate } from "../utils/date";
|
|
22
|
+
import { locale, rifmDateProps, t } from "../utils/i18n";
|
|
23
|
+
import { validateBooleanRequired, validateIndividualTaxNumber, validateNullableRequired, validateRequired, } from "../utils/validation";
|
|
24
|
+
import { AddressFormPart } from "./AddressFormPart";
|
|
25
|
+
import { CountryPicker } from "./CountryPicker";
|
|
26
|
+
import { LakeCityInput } from "./LakeCityInput";
|
|
27
|
+
const styles = StyleSheet.create({
|
|
28
|
+
inputContainer: {
|
|
29
|
+
flex: 1,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const beneficiaryTypes = [
|
|
33
|
+
{
|
|
34
|
+
value: "LegalRepresentative",
|
|
35
|
+
name: t("beneficiaryForm.beneficiary.legalRepresentative"),
|
|
36
|
+
},
|
|
37
|
+
{ value: "HasCapital", name: t("beneficiaryForm.beneficiary.ownershipOfCapital") },
|
|
38
|
+
{ value: "Other", name: t("beneficiaryForm.beneficiary.other") },
|
|
39
|
+
];
|
|
40
|
+
export const validateUbo = (editorState, accountCountry) => {
|
|
41
|
+
const isAddressRequired = accountCountry === "DEU";
|
|
42
|
+
return {
|
|
43
|
+
firstName: validateNullableRequired(editorState.firstName),
|
|
44
|
+
lastName: validateNullableRequired(editorState.lastName),
|
|
45
|
+
birthDate: validateNullableRequired(editorState.birthDate),
|
|
46
|
+
birthCountryCode: validateNullableRequired(editorState.birthCountryCode),
|
|
47
|
+
birthCity: validateNullableRequired(editorState.birthCity),
|
|
48
|
+
birthCityPostalCode: validateNullableRequired(editorState.birthCityPostalCode),
|
|
49
|
+
type: validateNullableRequired(editorState.type),
|
|
50
|
+
totalCapitalPercentage: editorState.type === "HasCapital"
|
|
51
|
+
? validateNullableRequired(editorState.totalCapitalPercentage?.toString())
|
|
52
|
+
: undefined,
|
|
53
|
+
residencyAddressLine1: isAddressRequired
|
|
54
|
+
? validateNullableRequired(editorState.residencyAddressLine1)
|
|
55
|
+
: undefined,
|
|
56
|
+
residencyAddressCity: isAddressRequired
|
|
57
|
+
? validateNullableRequired(editorState.residencyAddressCity)
|
|
58
|
+
: undefined,
|
|
59
|
+
residencyAddressCountry: isAddressRequired
|
|
60
|
+
? validateNullableRequired(editorState.residencyAddressCountry)
|
|
61
|
+
: undefined,
|
|
62
|
+
residencyAddressPostalCode: isAddressRequired
|
|
63
|
+
? validateNullableRequired(editorState.residencyAddressPostalCode)
|
|
64
|
+
: undefined,
|
|
65
|
+
taxIdentificationNumber: validateIndividualTaxNumber(editorState.taxIdentificationNumber ?? ""),
|
|
66
|
+
indirect: editorState.type !== "HasCapital" || editorState.direct === true
|
|
67
|
+
? undefined
|
|
68
|
+
: validateBooleanRequired(editorState.indirect),
|
|
69
|
+
direct: editorState.type !== "HasCapital" || editorState.indirect === true
|
|
70
|
+
? undefined
|
|
71
|
+
: validateBooleanRequired(editorState.direct),
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
const getCapitalType = (direct, indirect) => {
|
|
75
|
+
if (direct === true && indirect === true) {
|
|
76
|
+
return "both";
|
|
77
|
+
}
|
|
78
|
+
if (direct === true) {
|
|
79
|
+
return "direct";
|
|
80
|
+
}
|
|
81
|
+
if (indirect === true) {
|
|
82
|
+
return "indirect";
|
|
83
|
+
}
|
|
84
|
+
return "none";
|
|
85
|
+
};
|
|
86
|
+
const getDirectAndIndirect = (capitalType) => {
|
|
87
|
+
return match(capitalType)
|
|
88
|
+
.with("both", () => [true, true])
|
|
89
|
+
.with("direct", () => [true, false])
|
|
90
|
+
.with("indirect", () => [false, true])
|
|
91
|
+
.with("none", () => [false, false])
|
|
92
|
+
.exhaustive();
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* This component was created to handle validation easily with react-ux-form
|
|
96
|
+
* Without this component, we have to validate direct and indirect checkboxes separately
|
|
97
|
+
* But validation is run only onChange or onSubmit, so when both checkboxes were unchecked, check one of them doesn't revalidate the other one
|
|
98
|
+
* Another way is combining direct and indirect values with `formStatus` but the error appears or disappears too early
|
|
99
|
+
* So with this component we need only 1 validator making possible the best UX without caveats
|
|
100
|
+
*/
|
|
101
|
+
const CapitalTypeCheckboxes = ({ value, error, onChange }) => {
|
|
102
|
+
return (_jsxs(View, { children: [_jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(LakeLabelledCheckbox, { value: value === "direct" || value === "both", onValueChange: direct => {
|
|
103
|
+
match({ direct, value })
|
|
104
|
+
.with({ direct: true, value: "none" }, () => onChange("direct"))
|
|
105
|
+
.with({ direct: true, value: "indirect" }, () => onChange("both"))
|
|
106
|
+
.with({ direct: false, value: "direct" }, () => onChange("none"))
|
|
107
|
+
.with({ direct: false, value: "both" }, () => onChange("indirect"))
|
|
108
|
+
// other cases are impossible so we don't need to handle them
|
|
109
|
+
.otherwise(noop);
|
|
110
|
+
}, label: t("beneficiaryForm.beneficiary.directly"), isError: error != null }), _jsx(Space, { width: 24 }), _jsx(LakeLabelledCheckbox, { value: value === "indirect" || value === "both", onValueChange: indirect => {
|
|
111
|
+
match({ indirect, value })
|
|
112
|
+
.with({ indirect: true, value: "none" }, () => onChange("indirect"))
|
|
113
|
+
.with({ indirect: true, value: "direct" }, () => onChange("both"))
|
|
114
|
+
.with({ indirect: false, value: "indirect" }, () => onChange("none"))
|
|
115
|
+
.with({ indirect: false, value: "both" }, () => onChange("direct"))
|
|
116
|
+
// other cases are impossible so we don't need to handle them
|
|
117
|
+
.otherwise(noop);
|
|
118
|
+
}, label: t("beneficiaryForm.beneficiary.indirectly"), isError: error != null })] }), _jsx(Space, { height: 4 }), _jsx(LakeText, { color: colors.negative[400], children: error ?? " " })] }));
|
|
119
|
+
};
|
|
120
|
+
const formSteps = ["common", "address"];
|
|
121
|
+
const requiredStepFields = [
|
|
122
|
+
"firstName",
|
|
123
|
+
"lastName",
|
|
124
|
+
"birthDate",
|
|
125
|
+
"birthCountryCode",
|
|
126
|
+
"birthCity",
|
|
127
|
+
"birthCityPostalCode",
|
|
128
|
+
"type",
|
|
129
|
+
];
|
|
130
|
+
export const BeneficiaryForm = forwardRef(({ initialState, accountCountry, step, onStepChange, onClose, onSave, onCityLoadError }, ref) => {
|
|
131
|
+
const [reference] = useState(() => initialState?.reference ?? uuid());
|
|
132
|
+
const isAddressRequired = accountCountry === "DEU";
|
|
133
|
+
const commonStepValues = useRef();
|
|
134
|
+
const initialBirthDate = initialState?.birthDate;
|
|
135
|
+
const { Field, FieldsListener, setFieldValue, submitForm, listenFields, validateField } = useForm({
|
|
136
|
+
firstName: {
|
|
137
|
+
initialValue: initialState?.firstName ?? "",
|
|
138
|
+
validate: validateNullableRequired,
|
|
139
|
+
sanitize: value => value?.trim(),
|
|
140
|
+
},
|
|
141
|
+
lastName: {
|
|
142
|
+
initialValue: initialState?.lastName ?? "",
|
|
143
|
+
validate: validateNullableRequired,
|
|
144
|
+
sanitize: value => value?.trim(),
|
|
145
|
+
},
|
|
146
|
+
birthDate: {
|
|
147
|
+
initialValue: isNotNullishOrEmpty(initialBirthDate)
|
|
148
|
+
? decodeBirthDate(initialBirthDate)
|
|
149
|
+
: "",
|
|
150
|
+
validate: validateNullableRequired,
|
|
151
|
+
sanitize: value => value?.trim(),
|
|
152
|
+
},
|
|
153
|
+
birthCountryCode: {
|
|
154
|
+
initialValue: initialState?.birthCountryCode ?? accountCountry,
|
|
155
|
+
validate: validateNullableRequired,
|
|
156
|
+
},
|
|
157
|
+
birthCity: {
|
|
158
|
+
initialValue: initialState?.birthCity ?? "",
|
|
159
|
+
validate: validateNullableRequired,
|
|
160
|
+
sanitize: value => value?.trim(),
|
|
161
|
+
},
|
|
162
|
+
birthCityPostalCode: {
|
|
163
|
+
initialValue: initialState?.birthCityPostalCode ?? "",
|
|
164
|
+
validate: validateNullableRequired,
|
|
165
|
+
sanitize: value => value?.trim(),
|
|
166
|
+
},
|
|
167
|
+
type: {
|
|
168
|
+
initialValue: initialState?.type ?? "LegalRepresentative",
|
|
169
|
+
validate: validateRequired,
|
|
170
|
+
},
|
|
171
|
+
capitalType: {
|
|
172
|
+
initialValue: getCapitalType(initialState?.direct, initialState?.indirect),
|
|
173
|
+
validate: (value, { getFieldState }) => {
|
|
174
|
+
const type = getFieldState("type");
|
|
175
|
+
if (type.value === "HasCapital" && value === "none") {
|
|
176
|
+
return t("beneficiaryForm.beneficiary.directOrIndirect");
|
|
177
|
+
}
|
|
178
|
+
return undefined;
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
totalCapitalPercentage: {
|
|
182
|
+
initialValue: initialState?.totalCapitalPercentage?.toString(),
|
|
183
|
+
validate: validateNullableRequired,
|
|
184
|
+
sanitize: value => value?.trim(),
|
|
185
|
+
},
|
|
186
|
+
address: {
|
|
187
|
+
initialValue: initialState?.residencyAddressLine1,
|
|
188
|
+
validate: isAddressRequired ? validateNullableRequired : undefined,
|
|
189
|
+
sanitize: value => value?.trim(),
|
|
190
|
+
},
|
|
191
|
+
city: {
|
|
192
|
+
initialValue: initialState?.residencyAddressCity,
|
|
193
|
+
validate: isAddressRequired ? validateNullableRequired : undefined,
|
|
194
|
+
sanitize: value => value?.trim(),
|
|
195
|
+
},
|
|
196
|
+
postalCode: {
|
|
197
|
+
initialValue: initialState?.residencyAddressPostalCode,
|
|
198
|
+
validate: isAddressRequired ? validateNullableRequired : undefined,
|
|
199
|
+
sanitize: value => value?.trim(),
|
|
200
|
+
},
|
|
201
|
+
country: {
|
|
202
|
+
initialValue: isCountryCCA3(initialState?.residencyAddressCountry)
|
|
203
|
+
? initialState?.residencyAddressCountry
|
|
204
|
+
: accountCountry,
|
|
205
|
+
validate: isAddressRequired ? validateNullableRequired : undefined,
|
|
206
|
+
},
|
|
207
|
+
taxIdentificationNumber: {
|
|
208
|
+
initialValue: initialState?.taxIdentificationNumber,
|
|
209
|
+
validate: validateIndividualTaxNumber,
|
|
210
|
+
sanitize: value => value?.trim(),
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
const hasBeenSubmittedOnce = useRef(false);
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
return listenFields(["type"], () => {
|
|
216
|
+
if (hasBeenSubmittedOnce.current) {
|
|
217
|
+
// The setTimeout is needed here so that the `validateField`
|
|
218
|
+
// runs *after* the <Field /> mounts, as it's a no-op if not mounted
|
|
219
|
+
setTimeout(() => {
|
|
220
|
+
void validateField("totalCapitalPercentage");
|
|
221
|
+
}, 100);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}, [listenFields, validateField]);
|
|
225
|
+
useImperativeHandle(ref, () => {
|
|
226
|
+
return {
|
|
227
|
+
cancel: () => {
|
|
228
|
+
match(step)
|
|
229
|
+
.with("common", () => onClose())
|
|
230
|
+
.with("address", () => onStepChange("common"))
|
|
231
|
+
.exhaustive();
|
|
232
|
+
},
|
|
233
|
+
submit: () => {
|
|
234
|
+
hasBeenSubmittedOnce.current = true;
|
|
235
|
+
submitForm(values => {
|
|
236
|
+
if (step === "common" &&
|
|
237
|
+
isAddressRequired &&
|
|
238
|
+
hasDefinedKeys(values, requiredStepFields)) {
|
|
239
|
+
commonStepValues.current = values;
|
|
240
|
+
onStepChange("address");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const allStepsValues = { ...commonStepValues.current, ...values };
|
|
244
|
+
if (hasDefinedKeys(allStepsValues, requiredStepFields)) {
|
|
245
|
+
const [direct, indirect] = getDirectAndIndirect(values.capitalType ?? "none");
|
|
246
|
+
return onSave({
|
|
247
|
+
reference,
|
|
248
|
+
firstName: allStepsValues.firstName,
|
|
249
|
+
lastName: allStepsValues.lastName,
|
|
250
|
+
birthDate: encodeBirthDate(allStepsValues.birthDate),
|
|
251
|
+
birthCountryCode: allStepsValues.birthCountryCode,
|
|
252
|
+
birthCity: allStepsValues.birthCity,
|
|
253
|
+
birthCityPostalCode: allStepsValues.birthCityPostalCode,
|
|
254
|
+
type: allStepsValues.type,
|
|
255
|
+
indirect,
|
|
256
|
+
direct,
|
|
257
|
+
totalCapitalPercentage: isNotNullish(allStepsValues.totalCapitalPercentage)
|
|
258
|
+
? parseInt(allStepsValues.totalCapitalPercentage, 10)
|
|
259
|
+
: undefined,
|
|
260
|
+
residencyAddressLine1: allStepsValues.address,
|
|
261
|
+
residencyAddressCity: allStepsValues.city,
|
|
262
|
+
residencyAddressCountry: allStepsValues.country,
|
|
263
|
+
residencyAddressPostalCode: allStepsValues.postalCode,
|
|
264
|
+
taxIdentificationNumber: allStepsValues.taxIdentificationNumber,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
});
|
|
271
|
+
return (_jsx(ResponsiveContainer, { breakpoint: breakpoints.tiny, children: ({ small, large }) => (_jsxs(_Fragment, { children: [match(step)
|
|
272
|
+
.with("common", () => (_jsxs(View, { accessibilityRole: "form", children: [_jsxs(Box, { direction: small ? "column" : "row", children: [_jsx(Field, { name: "firstName", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.firstName"), style: styles.inputContainer, render: id => (_jsx(LakeTextInput, { error: error, placeholder: t("beneficiaryForm.beneficiary.firstNamePlaceholder"), nativeID: id, value: value, onChangeText: onChange })) })) }), _jsx(Space, { width: 12 }), _jsx(Field, { name: "lastName", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.lastName"), style: styles.inputContainer, render: id => (_jsx(LakeTextInput, { error: error, placeholder: t("beneficiaryForm.beneficiary.lastNamePlaceholder"), nativeID: id, value: value, onChangeText: onChange })) })) })] }), _jsxs(Box, { direction: small ? "column" : "row", children: [_jsx(Field, { name: "birthDate", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.birthDate"), style: styles.inputContainer, render: id => (_jsx(Rifm, { value: value ?? "", onChange: onChange, ...rifmDateProps, children: ({ value, onChange }) => (_jsx(LakeTextInput, { error: error, placeholder: locale.datePlaceholder, nativeID: id, value: value, onChange: onChange })) })) })) }), _jsx(Space, { width: 12 }), _jsx(Field, { name: "birthCountryCode", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.birthCountry"), style: styles.inputContainer, render: id => (_jsx(CountryPicker, { nativeID: id, error: error, value: value, placeholder: t("beneficiaryForm.beneficiary.birthCountryPlaceholder"), items: individualCountriesItems, onValueChange: onChange })) })) })] }), _jsx(Box, { direction: small ? "column" : "row", children: _jsx(FieldsListener, { names: ["birthCountryCode"], children: ({ birthCountryCode }) => (_jsxs(_Fragment, { children: [_jsx(Field, { name: "birthCity", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.birthCity"), style: styles.inputContainer, render: id => (_jsx(LakeCityInput, { nativeID: id, error: error, country: birthCountryCode.value, value: value ?? "", onValueChange: onChange, placeholder: birthCountryCode.value == null
|
|
273
|
+
? t("beneficiaryForm.beneficiary.fillBirthCountry")
|
|
274
|
+
: t("beneficiaryForm.beneficiary.birthCityPlaceholder"), onSuggestion: place => {
|
|
275
|
+
onChange(place.city);
|
|
276
|
+
setFieldValue("birthCityPostalCode", place.postalCode);
|
|
277
|
+
}, onLoadError: onCityLoadError })) })) }), _jsx(Space, { width: 12 }), _jsx(Field, { name: "birthCityPostalCode", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.birthPostalCode"), style: styles.inputContainer, render: id => (_jsx(LakeTextInput, { error: error, placeholder: birthCountryCode.value == null
|
|
278
|
+
? t("beneficiaryForm.beneficiary.fillBirthCountry")
|
|
279
|
+
: t("beneficiaryForm.beneficiary.birthPostalCodePlaceholder"), nativeID: id, disabled: birthCountryCode.value === undefined, value: value, onChangeText: onChange })) })) })] })) }) }), _jsx(Field, { name: "type", children: ({ value, onChange }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.type"), type: "radioGroup", render: () => (_jsx(RadioGroup, { direction: "row", value: value, onValueChange: onChange, items: beneficiaryTypes })) })) }), _jsx(FieldsListener, { names: ["type"], children: ({ type }) => type.value === "HasCapital" ? (_jsxs(_Fragment, { children: [_jsx(Field, { name: "totalCapitalPercentage", children: ({ value, onChange, error }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.totalCapitalPercentage"), render: id => (_jsx(LakeTextInput, { error: error, unit: "%", keyboardType: "decimal-pad", accessibilityValueMin: 0, accessibilityValueMax: 100, nativeID: id, value: value, onChangeText: onChange })) })) }), _jsx(Space, { height: 12 }), _jsx(Field, { name: "capitalType", children: ({ value, error, onChange }) => (_jsx(CapitalTypeCheckboxes, { value: value ?? "none", error: error, onChange: onChange })) })] })) : null })] })))
|
|
280
|
+
.with("address", () => (_jsxs(View, { accessibilityRole: "form", children: [_jsx(Field, { name: "country", children: ({ value, onChange }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.country"), render: id => (_jsx(CountryPicker, { nativeID: id, value: value, items: individualCountriesItems, onValueChange: onChange })) })) }), _jsx(Space, { height: 12 }), _jsx(FieldsListener, { names: ["country"], children: ({ country }) => (_jsxs(_Fragment, { children: [_jsx(AddressFormPart, { initialAddress: initialState?.residencyAddressLine1 ?? "", initialCity: initialState?.residencyAddressCity ?? "", initialPostalCode: initialState?.residencyAddressPostalCode ?? "", country: country?.value ?? accountCountry, label: t("beneficiaryForm.beneficiary.address"), Field: Field, setFieldValue: setFieldValue, listenFields: listenFields, isLarge: large }), country?.value === "DEU" && (_jsxs(_Fragment, { children: [_jsx(Space, { height: 12 }), _jsx(Field, { name: "taxIdentificationNumber", children: ({ value, error, valid, onChange }) => (_jsx(LakeLabel, { label: t("beneficiaryForm.beneficiary.taxIdentificationNumber"), optionalLabel: t("common.optional"), render: id => (_jsx(LakeTextInput, { nativeID: id, placeholder: t("beneficiaryForm.beneficiary.taxIdentificationNumberPlaceholder"), value: value, error: error, valid: valid, onChangeText: onChange })) })) })] }))] })) })] })))
|
|
281
|
+
.exhaustive(), isAddressRequired && (_jsxs(_Fragment, { children: [_jsx(Space, { height: 12 }), _jsx(StepDots, { currentStep: step, steps: formSteps })] }))] })) }));
|
|
282
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CountryCCA3 } from "../constants/countries";
|
|
3
|
+
type PlaceDetail = {
|
|
4
|
+
city: string;
|
|
5
|
+
postalCode: string;
|
|
6
|
+
};
|
|
7
|
+
type Props = {
|
|
8
|
+
value: string;
|
|
9
|
+
onValueChange: (value: string) => void;
|
|
10
|
+
country?: CountryCCA3;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
nativeID?: string;
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
onSuggestion?: (place: PlaceDetail) => void;
|
|
16
|
+
onLoadError: (error: unknown) => void;
|
|
17
|
+
apiKey?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const LakeCityInput: ({ value, onValueChange, country, disabled, placeholder, nativeID, error, onSuggestion, onLoadError, apiKey, }: Props) => JSX.Element | null;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AsyncData, Future } from "@swan-io/boxed";
|
|
3
|
+
import { useGoogleMapSDK } from "@swan-io/shared-business/src/hooks/useGoogleMapSDK";
|
|
4
|
+
import { AutoWidthImage } from "@swan-io/lake/src/components/AutoWidthImage";
|
|
5
|
+
import { Box } from "@swan-io/lake/src/components/Box";
|
|
6
|
+
import { LakeCombobox } from "@swan-io/lake/src/components/LakeCombobox";
|
|
7
|
+
import { colors } from "@swan-io/lake/src/constants/design";
|
|
8
|
+
import { typography } from "@swan-io/lake/src/constants/typography";
|
|
9
|
+
import { isNotNullish, isNullish } from "@swan-io/lake/src/utils/nullish";
|
|
10
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
11
|
+
import { StyleSheet, Text } from "react-native";
|
|
12
|
+
import { match } from "ts-pattern";
|
|
13
|
+
import poweredByGoogle from "../assets/images/powered_by_google_on_white_hdpi.png";
|
|
14
|
+
import { countriesWithMultipleCCA3 } from "../constants/countries";
|
|
15
|
+
import { t } from "../utils/i18n";
|
|
16
|
+
const styles = StyleSheet.create({
|
|
17
|
+
itemTitle: {
|
|
18
|
+
...typography.bodyLarge,
|
|
19
|
+
lineHeight: typography.lineHeights.title,
|
|
20
|
+
},
|
|
21
|
+
itemSubtitle: {
|
|
22
|
+
...typography.bodySmall,
|
|
23
|
+
color: colors.gray[400],
|
|
24
|
+
},
|
|
25
|
+
poweredByGoogle: {
|
|
26
|
+
paddingVertical: 8,
|
|
27
|
+
paddingHorizontal: 16,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
export const LakeCityInput = ({ value, onValueChange, country, disabled, placeholder, nativeID, error, onSuggestion, onLoadError, apiKey, }) => {
|
|
31
|
+
const [state, setState] = useState(AsyncData.NotAsked());
|
|
32
|
+
const comboboxRef = useRef(null);
|
|
33
|
+
const sdk = useGoogleMapSDK({ apiKey });
|
|
34
|
+
const autocomplete = useMemo(() => sdk.map(google => new google.maps.places.AutocompleteService()), [sdk]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (value.length <= 3) {
|
|
37
|
+
return setState(AsyncData.NotAsked());
|
|
38
|
+
}
|
|
39
|
+
setState(AsyncData.Loading());
|
|
40
|
+
if (isNotNullish(country)) {
|
|
41
|
+
const request = Future.make(resolve => {
|
|
42
|
+
const timeoutId = setTimeout(() => {
|
|
43
|
+
if (autocomplete.isDone()) {
|
|
44
|
+
Future.fromPromise(autocomplete.get().getPlacePredictions({
|
|
45
|
+
input: value,
|
|
46
|
+
componentRestrictions: {
|
|
47
|
+
country: [...(countriesWithMultipleCCA3[country] ?? "")],
|
|
48
|
+
},
|
|
49
|
+
types: ["(cities)"],
|
|
50
|
+
})).onResolve(resolve);
|
|
51
|
+
}
|
|
52
|
+
}, 250);
|
|
53
|
+
return () => clearTimeout(timeoutId);
|
|
54
|
+
}).mapOk(({ predictions }) => predictions.map(p => ({ value: p.place_id, prediction: p })), true);
|
|
55
|
+
request.tapError(onLoadError).onResolve(value => setState(AsyncData.Done(value)));
|
|
56
|
+
return () => request.cancel();
|
|
57
|
+
}
|
|
58
|
+
}, [country, value, autocomplete, onLoadError]);
|
|
59
|
+
return sdk.match({
|
|
60
|
+
NotAsked: () => null,
|
|
61
|
+
Loading: () => null,
|
|
62
|
+
Done: google => {
|
|
63
|
+
const place = new google.maps.places.PlacesService(document.createElement("div"));
|
|
64
|
+
const selectAddress = (suggestion) => {
|
|
65
|
+
place.getDetails({ placeId: suggestion.value }, placeDetail => {
|
|
66
|
+
const result = {
|
|
67
|
+
postalCode: "",
|
|
68
|
+
city: "",
|
|
69
|
+
};
|
|
70
|
+
placeDetail?.address_components?.forEach(({ types, short_name, long_name }) => {
|
|
71
|
+
const type = types[0];
|
|
72
|
+
match(type)
|
|
73
|
+
.with("postal_code", () => (result.postalCode = short_name))
|
|
74
|
+
.with("locality", () => (result.city = long_name))
|
|
75
|
+
.otherwise(() => { });
|
|
76
|
+
});
|
|
77
|
+
onSuggestion?.(result);
|
|
78
|
+
if (comboboxRef.current) {
|
|
79
|
+
comboboxRef.current.close();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
return (_jsx(LakeCombobox, { ref: comboboxRef, placeholder: placeholder, value: value, items: state, icon: "search-filled", disabled: isNullish(country) || disabled, error: error, onValueChange: onValueChange, nativeID: nativeID, ListFooterComponent: _jsx(Box, { direction: "row", justifyContent: "end", style: styles.poweredByGoogle, children: _jsx(AutoWidthImage, { height: 14, sourceUri: poweredByGoogle }) }), onSelectItem: selectAddress, emptyResultText: t("common.noResult"), keyExtractor: item => item.value, renderItem: item => (_jsxs(_Fragment, { children: [_jsx(Text, { numberOfLines: 1, selectable: false, style: styles.itemTitle, children: item.prediction.structured_formatting.main_text }), _jsx(Text, { numberOfLines: 1, selectable: false, style: styles.itemSubtitle, children: item.prediction.structured_formatting.secondary_text })] })) }));
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
};
|
|
@@ -24,7 +24,7 @@ type Props = {
|
|
|
24
24
|
requiredDocumentTypes: SupportingDocumentPurposeEnum[];
|
|
25
25
|
onChange?: (documents: Document[]) => void;
|
|
26
26
|
country?: CountryCCA3;
|
|
27
|
-
|
|
27
|
+
withoutRepresentationRadio?: boolean;
|
|
28
28
|
};
|
|
29
29
|
export type SupportingDocumentRef = {
|
|
30
30
|
submit: (callback: (value: boolean) => void) => void;
|
|
@@ -9,8 +9,8 @@ import { LakeText } from "@swan-io/lake/src/components/LakeText";
|
|
|
9
9
|
import { LakeTooltip } from "@swan-io/lake/src/components/LakeTooltip";
|
|
10
10
|
import { Pressable } from "@swan-io/lake/src/components/Pressable";
|
|
11
11
|
import { Space } from "@swan-io/lake/src/components/Space";
|
|
12
|
+
import { UploadArea } from "./UploadArea";
|
|
12
13
|
import { isNotNullish, isNullish } from "@swan-io/lake/src/utils/nullish";
|
|
13
|
-
import { UploadArea } from "@swan-io/shared-business/src/components/UploadArea";
|
|
14
14
|
import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
|
|
15
15
|
import { StyleSheet } from "react-native";
|
|
16
16
|
import { useForm } from "react-ux-form";
|
|
@@ -32,10 +32,10 @@ const styles = StyleSheet.create({
|
|
|
32
32
|
cursor: "default",
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
|
-
const Help = ({ text, width, onPress, }) => {
|
|
36
|
-
return (_jsx(LakeTooltip, { content: t(text), width: width, togglableOnFocus: true, placement: "top", children: _jsx(LakeButton, { mode: "tertiary", color: "gray", icon: "question-circle-regular", onPress: onPress, disabled: onPress == null, style: [styles.button, onPress == null && styles.buttonWithDefaultCursor], accessibilityLabel: t("supportingDoc.whatIsThis") }) }));
|
|
35
|
+
const Help = ({ text, label, width, onPress, }) => {
|
|
36
|
+
return (_jsx(LakeTooltip, { content: t(text), width: width, togglableOnFocus: true, placement: "top", children: _jsx(LakeButton, { mode: "tertiary", size: "small", color: "gray", icon: "question-circle-regular", onPress: onPress, disabled: onPress == null, style: [styles.button, onPress == null && styles.buttonWithDefaultCursor], accessibilityLabel: t("supportingDoc.whatIsThis"), children: label }) }));
|
|
37
37
|
};
|
|
38
|
-
export const SupportingDocument = forwardRef(({ documents, getAwsUrl, onChange, requiredDocumentTypes, country,
|
|
38
|
+
export const SupportingDocument = forwardRef(({ documents, getAwsUrl, onChange, requiredDocumentTypes, country, withoutRepresentationRadio }, externalRef) => {
|
|
39
39
|
const initialValues = useMemo(() => documents.reduce((acc, doc) => {
|
|
40
40
|
return {
|
|
41
41
|
...acc,
|
|
@@ -147,7 +147,7 @@ export const SupportingDocument = forwardRef(({ documents, getAwsUrl, onChange,
|
|
|
147
147
|
})
|
|
148
148
|
.catch(console.error);
|
|
149
149
|
};
|
|
150
|
-
return (_jsxs(Form, { children: [
|
|
150
|
+
return (_jsxs(Form, { children: [withoutRepresentationRadio !== true && (_jsx(LakeLabel, { label: t("supportingDoc.whoAreYou"), render: () => (_jsxs(LakeButtonGroup, { children: [_jsx(Pressable, { onPress: () => setIsOther(false), children: _jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(LakeRadio, { value: !isOther, color: "current" }), _jsx(Space, { width: 12 }), _jsx(LakeText, { children: t("supportingDoc.legalRepresentative") })] }) }), _jsx(Space, { width: 24 }), _jsx(Pressable, { onPress: () => setIsOther(true), children: _jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(LakeRadio, { value: isOther, color: "current" }), _jsx(Space, { width: 12 }), _jsx(LakeText, { children: t("supportingDoc.other") })] }) })] })) })), requiredDocumentTypes.some(t => t === "CompanyRegistration") && (_jsxs(_Fragment, { children: [_jsx(LakeLabel, { label: t("supportingDoc.companyRegistration"), help: _jsx(Help, { text: "supportingDoc.companyRegistration.description" }), render: () => (_jsx(Field, { name: "CompanyRegistration", children: ({ value, onChange, error }) => (_jsx(UploadArea, { layout: "horizontal", error: error, onDropAccepted: files => {
|
|
151
151
|
onChange([...value, { id: NO_ID_YET }]);
|
|
152
152
|
handleUpload(files, "CompanyRegistration");
|
|
153
153
|
}, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 })] })), requiredDocumentTypes.some(t => t === "AssociationRegistration") && (_jsxs(_Fragment, { children: [_jsx(LakeLabel, { label: t("supportingDoc.associationRegistration"), help: _jsx(Help, { text: "supportingDoc.associationRegistration.description" }), render: () => (_jsx(Field, { name: "AssociationRegistration", children: ({ value, onChange, error }) => (_jsx(UploadArea, { layout: "horizontal", onDropAccepted: files => {
|
|
@@ -156,11 +156,11 @@ export const SupportingDocument = forwardRef(({ documents, getAwsUrl, onChange,
|
|
|
156
156
|
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 })] })), requiredDocumentTypes.some(t => t === "SignedStatus") && (_jsxs(_Fragment, { children: [_jsx(LakeLabel, { label: t("supportingDoc.signedStatus"), help: _jsx(Help, { text: "supportingDoc.signedStatus.description" }), render: () => (_jsx(Field, { name: "SignedStatus", children: ({ value, onChange, error }) => (_jsx(UploadArea, { layout: "horizontal", onDropAccepted: files => {
|
|
157
157
|
onChange([...value, { id: NO_ID_YET }]);
|
|
158
158
|
handleUpload(files, "SignedStatus");
|
|
159
|
-
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 })] })), requiredDocumentTypes.
|
|
159
|
+
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 })] })), (requiredDocumentTypes.some(t => t === "ProofOfIdentity") || isOther) && (_jsxs(_Fragment, { children: [_jsx(LakeLabel, { label: t("supportingDoc.proofOfIdentity"), help: _jsx(Help, { width: 600, text: "supportingDoc.proofOfIdentity.description" }), render: () => (_jsx(Field, { name: "ProofOfIdentity", children: ({ value, onChange, error }) => (_jsx(UploadArea, { layout: "horizontal", onDropAccepted: files => {
|
|
160
160
|
onChange([...value, { id: NO_ID_YET }]);
|
|
161
161
|
handleUpload(files, "ProofOfIdentity");
|
|
162
|
-
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 }), _jsx(LakeLabel, { label: t("supportingDoc.powerAttornySigned"), help: _jsx(Help, { text: "supportingDoc.powerAttornySigned.description", onPress: () => setShowPowerOfAttorneyModal(true) }), render: () => (_jsx(Field, { name: "Other", children: ({ value, onChange, error }) => (_jsx(UploadArea, { layout: "horizontal", onDropAccepted: files => {
|
|
162
|
+
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 })] })), (requiredDocumentTypes.some(t => t === "PowerOfAttorney") || isOther) && (_jsxs(_Fragment, { children: [_jsx(LakeLabel, { label: t("supportingDoc.powerAttornySigned"), help: _jsx(Help, { text: "supportingDoc.powerAttornySigned.description", label: t("supportingDoc.whatIsThis"), onPress: () => setShowPowerOfAttorneyModal(true) }), render: () => (_jsx(Field, { name: "Other", children: ({ value, onChange, error }) => (_jsx(UploadArea, { layout: "horizontal", onDropAccepted: files => {
|
|
163
163
|
onChange([...value, { id: NO_ID_YET }]);
|
|
164
164
|
handleUpload(files, "Other");
|
|
165
|
-
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsxs(LakeModal, { visible: showPowerOfAttorneyModal, title: t("supportingDoc.powerAttorney"), icon: "document-regular", onPressClose: () => setShowPowerOfAttorneyModal(false), children: [_jsx(LakeText, { children: t("supportingDoc.powerAttornySigned.description") }), _jsx(Space, { height: 16 }), _jsx(LakeButtonGroup, { paddingBottom: 0, children: _jsx(LakeButton, { grow: true, color: "current", onPress: () => window.open(`/power-of-attorney-template/${country === "FRA" ? "fr" : "en"}.pdf`), children: t("supportingDoc.downloadTemplate") }) })] })] }))
|
|
165
|
+
}, error: error, documents: value, accept: ACCEPTED_FORMATS, icon: "document-regular", description: t("supportingDoc.documentTypes"), maxSize: MAX_SUPPORTING_DOCUMENT_UPLOAD_SIZE })) })) }), _jsx(Space, { height: 24 })] })), requiredDocumentTypes.length === 0 && (!isOther || withoutRepresentationRadio === true) ? (_jsxs(_Fragment, { children: [_jsx(Space, { height: 24 }), _jsx(LakeText, { children: t("supportingDoc.noRequiredDocuments") }), _jsx(Space, { height: 24 })] })) : null, _jsxs(LakeModal, { visible: showPowerOfAttorneyModal, title: t("supportingDoc.powerAttorney"), icon: "document-regular", onPressClose: () => setShowPowerOfAttorneyModal(false), children: [_jsx(LakeText, { children: t("supportingDoc.powerAttornySigned.description") }), _jsx(Space, { height: 16 }), _jsx(LakeButtonGroup, { paddingBottom: 0, children: _jsx(LakeButton, { grow: true, color: "current", onPress: () => window.open(`/power-of-attorney-template/${country === "FRA" ? "fr" : "en"}.pdf`), children: t("supportingDoc.downloadTemplate") }) })] })] }));
|
|
166
166
|
});
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { formatNestedMessage, t } from "../utils/i18n";
|
|
2
3
|
import { Box } from "@swan-io/lake/src/components/Box";
|
|
3
|
-
import { FileTile } from "@swan-io/lake/src/components/FileTile";
|
|
4
4
|
import { Icon } from "@swan-io/lake/src/components/Icon";
|
|
5
5
|
import { LakeHeading } from "@swan-io/lake/src/components/LakeHeading";
|
|
6
6
|
import { LakeText } from "@swan-io/lake/src/components/LakeText";
|
|
7
7
|
import { Space } from "@swan-io/lake/src/components/Space";
|
|
8
|
-
import { commonStyles } from "@swan-io/lake/src/constants/commonStyles";
|
|
9
8
|
import { backgroundColor, colors, gray75, radii, shadows, spacings, } from "@swan-io/lake/src/constants/design";
|
|
10
|
-
import { useBoolean } from "@swan-io/lake/src/hooks/useBoolean";
|
|
11
|
-
import { getIconNameFromFilename } from "@swan-io/lake/src/utils/file";
|
|
12
9
|
import { isNotNullish, isNullish } from "@swan-io/lake/src/utils/nullish";
|
|
13
|
-
import { formatNestedMessage, t } from "@swan-io/shared-business/src/utils/i18n";
|
|
14
10
|
import { Fragment, useLayoutEffect, useRef } from "react";
|
|
15
11
|
import { useDropzone } from "react-dropzone";
|
|
16
12
|
import { StyleSheet, Text, View } from "react-native";
|
|
13
|
+
import { commonStyles } from "@swan-io/lake/src/constants/commonStyles";
|
|
14
|
+
import { useBoolean } from "@swan-io/lake/src/hooks/useBoolean";
|
|
15
|
+
import { getIconNameFromFilename } from "@swan-io/lake/src/utils/file";
|
|
16
|
+
import { FileTile } from "@swan-io/lake/src/components/FileTile";
|
|
17
17
|
const styles = StyleSheet.create({
|
|
18
18
|
container: {
|
|
19
19
|
backgroundColor: backgroundColor.accented,
|
|
@@ -1981,22 +1981,22 @@ export type Country = (typeof countries)[number];
|
|
|
1981
1981
|
export type CountryCCA2 = (typeof countries)[number]["cca2"];
|
|
1982
1982
|
export type CountryCCA3 = (typeof countries)[number]["cca3"];
|
|
1983
1983
|
export declare const getCCA2forCCA3: (cca3: CountryCCA3) => "BA" | "CA" | "ID" | "AX" | "AS" | "AD" | "AO" | "AI" | "AQ" | "AG" | "AR" | "AW" | "AU" | "AZ" | "BS" | "BD" | "BB" | "BE" | "BZ" | "BJ" | "BM" | "BO" | "BQ" | "BW" | "BV" | "BR" | "VG" | "BF" | "BI" | "CV" | "CM" | "KY" | "CZ" | "CL" | "CX" | "CC" | "CO" | "CK" | "CR" | "CI" | "CU" | "CW" | "DK" | "DE" | "DJ" | "DM" | "EC" | "EE" | "IE" | "SV" | "ES" | "FK" | "FJ" | "FO" | "FR" | "GA" | "GM" | "GH" | "GI" | "GD" | "GP" | "GU" | "GT" | "GG" | "GW" | "GQ" | "GN" | "GY" | "GF" | "HT" | "HM" | "HN" | "HR" | "IS" | "IM" | "IT" | "JM" | "JE" | "GL" | "KH" | "KZ" | "KE" | "KI" | "CF" | "KM" | "RE" | "LV" | "LS" | "LR" | "LI" | "LT" | "LU" | "MG" | "HU" | "MH" | "MW" | "MY" | "MV" | "ML" | "MT" | "MQ" | "MU" | "YT" | "MX" | "FM" | "MZ" | "MD" | "MC" | "MS" | "NA" | "NL" | "BN" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "NO" | "MP" | "NC" | "AT" | "UZ" | "PK" | "PW" | "PA" | "PG" | "PY" | "PE" | "PH" | "PN" | "PL" | "PF" | "PT" | "PR" | "DO" | "XK" | "CD" | "CG" | "RO" | "RW" | "KN" | "LC" | "VC" | "BL" | "MF" | "PM" | "WS" | "SM" | "ST" | "CH" | "SN" | "SC" | "AL" | "SL" | "SG" | "SI" | "SK" | "SB" | "SO" | "ZA" | "GS" | "SS" | "LK" | "FI" | "SR" | "SE" | "SZ" | "TZ" | "TD" | "TF" | "TL" | "TG" | "TO" | "TT" | "TR" | "TM" | "TC" | "TV" | "UG" | "GB" | "US" | "UM" | "VI" | "UY" | "VU" | "VA" | "VE" | "VN" | "WF" | "ZM" | "ZW" | "BT" | "GR" | "CY" | "BY" | "BG" | "KG" | "MK" | "MN" | "RU" | "RS" | "TJ" | "UA" | "ME" | "AM" | "IL" | "AF" | "JO" | "DZ" | "SD" | "EH" | "IQ" | "SA" | "KW" | "MA" | "YE" | "IR" | "TN" | "AE" | "SY" | "OM" | "PS" | "QA" | "LB" | "EG" | "MR" | "NP" | "IN" | "TH" | "LA" | "MM" | "GE" | "ET" | "ER" | "BH" | "LY" | "CN" | "JP" | "MO" | "TW" | "HK" | "KR" | "KP" | undefined;
|
|
1984
|
-
export declare const getCCA3forCCA2: (cca2: CountryCCA2) => "ALA" | "ASM" | "AND" | "AGO" | "AIA" | "ATA" | "ATG" | "ARG" | "ABW" | "AUS" | "AZE" | "BHS" | "BGD" | "BRB" | "BEL" | "BLZ" | "BEN" | "BMU" | "BOL" | "BES" | "BIH" | "BWA" | "BVT" | "BRA" | "VGB" | "BFA" | "BDI" | "CPV" | "CMR" | "CAN" | "CYM" | "CZE" | "CHL" | "CXR" | "CCK" | "COL" | "COK" | "CRI" | "CIV" | "CUB" | "CUW" | "DNK" | "DEU" | "DJI" | "DMA" | "ECU" | "EST" | "IRL" | "SLV" | "ESP" | "FLK" | "FJI" | "FRO" | "FRA" | "GAB" | "GMB" | "GHA" | "GIB" | "GRD" | "GLP" | "GUM" | "GTM" | "GGY" | "GNB" | "GNQ" | "GIN" | "GUY" | "GUF" | "HTI" | "HMD" | "HND" | "HRV" | "IDN" | "ISL" | "IMN" | "ITA" | "JAM" | "JEY" | "GRL" | "KHM" | "KAZ" | "KEN" | "KIR" | "CAF" | "COM" | "REU" | "LVA" | "LSO" | "LBR" | "LIE" | "LTU" | "LUX" | "MDG" | "HUN" | "MHL" | "MWI" | "MYS" | "MDV" | "MLI" | "MLT" | "MTQ" | "MUS" | "MYT" | "MEX" | "FSM" | "MOZ" | "MDA" | "MCO" | "MSR" | "NAM" | "NLD" | "BRN" | "NZL" | "NIC" | "NER" | "NGA" | "NIU" | "NFK" | "NOR" | "MNP" | "NCL" | "AUT" | "UZB" | "PAK" | "PLW" | "PAN" | "
|
|
1984
|
+
export declare const getCCA3forCCA2: (cca2: CountryCCA2) => "PNG" | "ALA" | "ASM" | "AND" | "AGO" | "AIA" | "ATA" | "ATG" | "ARG" | "ABW" | "AUS" | "AZE" | "BHS" | "BGD" | "BRB" | "BEL" | "BLZ" | "BEN" | "BMU" | "BOL" | "BES" | "BIH" | "BWA" | "BVT" | "BRA" | "VGB" | "BFA" | "BDI" | "CPV" | "CMR" | "CAN" | "CYM" | "CZE" | "CHL" | "CXR" | "CCK" | "COL" | "COK" | "CRI" | "CIV" | "CUB" | "CUW" | "DNK" | "DEU" | "DJI" | "DMA" | "ECU" | "EST" | "IRL" | "SLV" | "ESP" | "FLK" | "FJI" | "FRO" | "FRA" | "GAB" | "GMB" | "GHA" | "GIB" | "GRD" | "GLP" | "GUM" | "GTM" | "GGY" | "GNB" | "GNQ" | "GIN" | "GUY" | "GUF" | "HTI" | "HMD" | "HND" | "HRV" | "IDN" | "ISL" | "IMN" | "ITA" | "JAM" | "JEY" | "GRL" | "KHM" | "KAZ" | "KEN" | "KIR" | "CAF" | "COM" | "REU" | "LVA" | "LSO" | "LBR" | "LIE" | "LTU" | "LUX" | "MDG" | "HUN" | "MHL" | "MWI" | "MYS" | "MDV" | "MLI" | "MLT" | "MTQ" | "MUS" | "MYT" | "MEX" | "FSM" | "MOZ" | "MDA" | "MCO" | "MSR" | "NAM" | "NLD" | "BRN" | "NZL" | "NIC" | "NER" | "NGA" | "NIU" | "NFK" | "NOR" | "MNP" | "NCL" | "AUT" | "UZB" | "PAK" | "PLW" | "PAN" | "PRY" | "PER" | "PHL" | "PCN" | "POL" | "PYF" | "PRT" | "PRI" | "DOM" | "UNK" | "COD" | "COG" | "ROU" | "RWA" | "KNA" | "LCA" | "VCT" | "BLM" | "MAF" | "SPM" | "WSM" | "SMR" | "STP" | "CHE" | "SEN" | "SYC" | "ALB" | "SLE" | "SGP" | "SVN" | "SVK" | "SLB" | "SOM" | "ZAF" | "SGS" | "SSD" | "LKA" | "FIN" | "SUR" | "SWE" | "SWZ" | "TZA" | "TCD" | "ATF" | "TLS" | "TGO" | "TON" | "TTO" | "TUR" | "TKM" | "TCA" | "TUV" | "UGA" | "GBR" | "USA" | "UMI" | "VIR" | "URY" | "VUT" | "VAT" | "VEN" | "VNM" | "WLF" | "ZMB" | "ZWE" | "BTN" | "GRC" | "CYP" | "BLR" | "BGR" | "KGZ" | "MKD" | "MNG" | "RUS" | "SRB" | "TJK" | "UKR" | "MNE" | "ARM" | "ISR" | "AFG" | "JOR" | "DZA" | "SDN" | "ESH" | "IRQ" | "SAU" | "KWT" | "MAR" | "YEM" | "IRN" | "TUN" | "ARE" | "SYR" | "OMN" | "PSE" | "QAT" | "LBN" | "EGY" | "MRT" | "NPL" | "IND" | "THA" | "LAO" | "MMR" | "GEO" | "ETH" | "ERI" | "BHR" | "LBY" | "CHN" | "JPN" | "MAC" | "TWN" | "HKG" | "KOR" | "PRK" | undefined;
|
|
1985
1985
|
export declare const getCountryNameByCCA3: (cca3: string) => string;
|
|
1986
1986
|
export declare const companyWithUboCountries: readonly ["BEL", "DEU", "FRA", "ITA", "LTU", "LUX", "NLD"];
|
|
1987
1987
|
export type CompanyWithUboCountryCCA3 = (typeof companyWithUboCountries)[number];
|
|
1988
1988
|
declare const individualCountries: ("BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "NOR" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "CYP" | "BGR")[];
|
|
1989
1989
|
export type IndividualCountryCCA3 = (typeof individualCountries)[number];
|
|
1990
1990
|
export declare const individualCountriesItems: CountryItem<IndividualCountryCCA3>[];
|
|
1991
|
-
declare const companyCountries: ("BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "BGR")[];
|
|
1991
|
+
declare const companyCountries: ("BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "NOR" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "CYP" | "BGR")[];
|
|
1992
1992
|
export type CompanyCountryCCA3 = (typeof companyCountries)[number];
|
|
1993
1993
|
export declare const companyCountriesItems: CountryItem<CompanyCountryCCA3>[];
|
|
1994
1994
|
export declare const countriesWithMultipleCCA3: Partial<Record<CountryCCA3, string[]>>;
|
|
1995
|
-
export declare const isCountryCCA3: (value: unknown) => value is "ALA" | "ASM" | "AND" | "AGO" | "AIA" | "ATA" | "ATG" | "ARG" | "ABW" | "AUS" | "AZE" | "BHS" | "BGD" | "BRB" | "BEL" | "BLZ" | "BEN" | "BMU" | "BOL" | "BES" | "BIH" | "BWA" | "BVT" | "BRA" | "VGB" | "BFA" | "BDI" | "CPV" | "CMR" | "CAN" | "CYM" | "CZE" | "CHL" | "CXR" | "CCK" | "COL" | "COK" | "CRI" | "CIV" | "CUB" | "CUW" | "DNK" | "DEU" | "DJI" | "DMA" | "ECU" | "EST" | "IRL" | "SLV" | "ESP" | "FLK" | "FJI" | "FRO" | "FRA" | "GAB" | "GMB" | "GHA" | "GIB" | "GRD" | "GLP" | "GUM" | "GTM" | "GGY" | "GNB" | "GNQ" | "GIN" | "GUY" | "GUF" | "HTI" | "HMD" | "HND" | "HRV" | "IDN" | "ISL" | "IMN" | "ITA" | "JAM" | "JEY" | "GRL" | "KHM" | "KAZ" | "KEN" | "KIR" | "CAF" | "COM" | "REU" | "LVA" | "LSO" | "LBR" | "LIE" | "LTU" | "LUX" | "MDG" | "HUN" | "MHL" | "MWI" | "MYS" | "MDV" | "MLI" | "MLT" | "MTQ" | "MUS" | "MYT" | "MEX" | "FSM" | "MOZ" | "MDA" | "MCO" | "MSR" | "NAM" | "NLD" | "BRN" | "NZL" | "NIC" | "NER" | "NGA" | "NIU" | "NFK" | "NOR" | "MNP" | "NCL" | "AUT" | "UZB" | "PAK" | "PLW" | "PAN" | "
|
|
1995
|
+
export declare const isCountryCCA3: (value: unknown) => value is "PNG" | "ALA" | "ASM" | "AND" | "AGO" | "AIA" | "ATA" | "ATG" | "ARG" | "ABW" | "AUS" | "AZE" | "BHS" | "BGD" | "BRB" | "BEL" | "BLZ" | "BEN" | "BMU" | "BOL" | "BES" | "BIH" | "BWA" | "BVT" | "BRA" | "VGB" | "BFA" | "BDI" | "CPV" | "CMR" | "CAN" | "CYM" | "CZE" | "CHL" | "CXR" | "CCK" | "COL" | "COK" | "CRI" | "CIV" | "CUB" | "CUW" | "DNK" | "DEU" | "DJI" | "DMA" | "ECU" | "EST" | "IRL" | "SLV" | "ESP" | "FLK" | "FJI" | "FRO" | "FRA" | "GAB" | "GMB" | "GHA" | "GIB" | "GRD" | "GLP" | "GUM" | "GTM" | "GGY" | "GNB" | "GNQ" | "GIN" | "GUY" | "GUF" | "HTI" | "HMD" | "HND" | "HRV" | "IDN" | "ISL" | "IMN" | "ITA" | "JAM" | "JEY" | "GRL" | "KHM" | "KAZ" | "KEN" | "KIR" | "CAF" | "COM" | "REU" | "LVA" | "LSO" | "LBR" | "LIE" | "LTU" | "LUX" | "MDG" | "HUN" | "MHL" | "MWI" | "MYS" | "MDV" | "MLI" | "MLT" | "MTQ" | "MUS" | "MYT" | "MEX" | "FSM" | "MOZ" | "MDA" | "MCO" | "MSR" | "NAM" | "NLD" | "BRN" | "NZL" | "NIC" | "NER" | "NGA" | "NIU" | "NFK" | "NOR" | "MNP" | "NCL" | "AUT" | "UZB" | "PAK" | "PLW" | "PAN" | "PRY" | "PER" | "PHL" | "PCN" | "POL" | "PYF" | "PRT" | "PRI" | "DOM" | "UNK" | "COD" | "COG" | "ROU" | "RWA" | "KNA" | "LCA" | "VCT" | "BLM" | "MAF" | "SPM" | "WSM" | "SMR" | "STP" | "CHE" | "SEN" | "SYC" | "ALB" | "SLE" | "SGP" | "SVN" | "SVK" | "SLB" | "SOM" | "ZAF" | "SGS" | "SSD" | "LKA" | "FIN" | "SUR" | "SWE" | "SWZ" | "TZA" | "TCD" | "ATF" | "TLS" | "TGO" | "TON" | "TTO" | "TUR" | "TKM" | "TCA" | "TUV" | "UGA" | "GBR" | "USA" | "UMI" | "VIR" | "URY" | "VUT" | "VAT" | "VEN" | "VNM" | "WLF" | "ZMB" | "ZWE" | "BTN" | "GRC" | "CYP" | "BLR" | "BGR" | "KGZ" | "MKD" | "MNG" | "RUS" | "SRB" | "TJK" | "UKR" | "MNE" | "ARM" | "ISR" | "AFG" | "JOR" | "DZA" | "SDN" | "ESH" | "IRQ" | "SAU" | "KWT" | "MAR" | "YEM" | "IRN" | "TUN" | "ARE" | "SYR" | "OMN" | "PSE" | "QAT" | "LBN" | "EGY" | "MRT" | "NPL" | "IND" | "THA" | "LAO" | "MMR" | "GEO" | "ETH" | "ERI" | "BHR" | "LBY" | "CHN" | "JPN" | "MAC" | "TWN" | "HKG" | "KOR" | "PRK";
|
|
1996
1996
|
export declare const isCountryCCA2: (value: unknown) => value is "BA" | "CA" | "ID" | "AX" | "AS" | "AD" | "AO" | "AI" | "AQ" | "AG" | "AR" | "AW" | "AU" | "AZ" | "BS" | "BD" | "BB" | "BE" | "BZ" | "BJ" | "BM" | "BO" | "BQ" | "BW" | "BV" | "BR" | "VG" | "BF" | "BI" | "CV" | "CM" | "KY" | "CZ" | "CL" | "CX" | "CC" | "CO" | "CK" | "CR" | "CI" | "CU" | "CW" | "DK" | "DE" | "DJ" | "DM" | "EC" | "EE" | "IE" | "SV" | "ES" | "FK" | "FJ" | "FO" | "FR" | "GA" | "GM" | "GH" | "GI" | "GD" | "GP" | "GU" | "GT" | "GG" | "GW" | "GQ" | "GN" | "GY" | "GF" | "HT" | "HM" | "HN" | "HR" | "IS" | "IM" | "IT" | "JM" | "JE" | "GL" | "KH" | "KZ" | "KE" | "KI" | "CF" | "KM" | "RE" | "LV" | "LS" | "LR" | "LI" | "LT" | "LU" | "MG" | "HU" | "MH" | "MW" | "MY" | "MV" | "ML" | "MT" | "MQ" | "MU" | "YT" | "MX" | "FM" | "MZ" | "MD" | "MC" | "MS" | "NA" | "NL" | "BN" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "NO" | "MP" | "NC" | "AT" | "UZ" | "PK" | "PW" | "PA" | "PG" | "PY" | "PE" | "PH" | "PN" | "PL" | "PF" | "PT" | "PR" | "DO" | "XK" | "CD" | "CG" | "RO" | "RW" | "KN" | "LC" | "VC" | "BL" | "MF" | "PM" | "WS" | "SM" | "ST" | "CH" | "SN" | "SC" | "AL" | "SL" | "SG" | "SI" | "SK" | "SB" | "SO" | "ZA" | "GS" | "SS" | "LK" | "FI" | "SR" | "SE" | "SZ" | "TZ" | "TD" | "TF" | "TL" | "TG" | "TO" | "TT" | "TR" | "TM" | "TC" | "TV" | "UG" | "GB" | "US" | "UM" | "VI" | "UY" | "VU" | "VA" | "VE" | "VN" | "WF" | "ZM" | "ZW" | "BT" | "GR" | "CY" | "BY" | "BG" | "KG" | "MK" | "MN" | "RU" | "RS" | "TJ" | "UA" | "ME" | "AM" | "IL" | "AF" | "JO" | "DZ" | "SD" | "EH" | "IQ" | "SA" | "KW" | "MA" | "YE" | "IR" | "TN" | "AE" | "SY" | "OM" | "PS" | "QA" | "LB" | "EG" | "MR" | "NP" | "IN" | "TH" | "LA" | "MM" | "GE" | "ET" | "ER" | "BH" | "LY" | "CN" | "JP" | "MO" | "TW" | "HK" | "KR" | "KP";
|
|
1997
1997
|
export declare const isIndividualCountryCCA3: (value: unknown) => value is "BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "NOR" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "CYP" | "BGR";
|
|
1998
|
-
export declare const isCompanyCountryCCA3: (value: unknown) => value is "BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "BGR";
|
|
1998
|
+
export declare const isCompanyCountryCCA3: (value: unknown) => value is "BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "NOR" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "CYP" | "BGR";
|
|
1999
1999
|
export declare const isCompanyWithUboCountryCCA3: (value: unknown) => value is "BEL" | "DEU" | "FRA" | "ITA" | "LTU" | "LUX" | "NLD";
|
|
2000
2000
|
export declare const individualFallbackCountry: "BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "NOR" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "CYP" | "BGR";
|
|
2001
|
-
export declare const companyFallbackCountry: "BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "BGR";
|
|
2001
|
+
export declare const companyFallbackCountry: "BEL" | "CZE" | "DNK" | "DEU" | "EST" | "IRL" | "ESP" | "FRA" | "HRV" | "ISL" | "ITA" | "LVA" | "LIE" | "LTU" | "LUX" | "HUN" | "MLT" | "NLD" | "NOR" | "AUT" | "POL" | "PRT" | "ROU" | "SVN" | "SVK" | "FIN" | "SWE" | "GRC" | "CYP" | "BGR";
|
|
2002
2002
|
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AsyncData } from "@swan-io/boxed";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { atom, useAtom } from "react-atomic-state";
|
|
4
|
+
import { Loader } from "@googlemaps/js-api-loader";
|
|
5
|
+
const sdk = atom(AsyncData.NotAsked());
|
|
6
|
+
export const useGoogleMapSDK = ({ language, apiKey }) => {
|
|
7
|
+
const googleSdk = useAtom(sdk);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (googleSdk.isNotAsked()) {
|
|
10
|
+
if (apiKey != undefined) {
|
|
11
|
+
sdk.set(AsyncData.Loading());
|
|
12
|
+
void new Loader({
|
|
13
|
+
apiKey,
|
|
14
|
+
language,
|
|
15
|
+
})
|
|
16
|
+
.load()
|
|
17
|
+
.then(google => sdk.set(AsyncData.Done(google)));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, [language, googleSdk, apiKey]);
|
|
21
|
+
return googleSdk;
|
|
22
|
+
};
|
package/src/utils/i18n.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RifmProps } from "@swan-io/lake/src/utils/rifm";
|
|
2
2
|
import { ReactElement, ReactNode } from "react";
|
|
3
3
|
import translationEN from "../locales/en.json";
|
|
4
4
|
declare const supportedLanguages: readonly ["en", "es", "de", "fr", "it", "nl", "pt"];
|
|
5
|
-
type SupportedLanguage =
|
|
5
|
+
type SupportedLanguage = typeof supportedLanguages[number];
|
|
6
6
|
type TranslationParams = Record<string, string | number>;
|
|
7
7
|
export type TranslationKey = keyof typeof translationEN;
|
|
8
8
|
type Locale = {
|
|
@@ -17,5 +17,5 @@ type Locale = {
|
|
|
17
17
|
export declare const locale: Locale;
|
|
18
18
|
export declare const t: (key: TranslationKey, params?: TranslationParams) => string;
|
|
19
19
|
export declare const formatNestedMessage: (key: TranslationKey, params: Record<string, string | number | ReactElement<any, string | import("react").JSXElementConstructor<any>> | ((children: ReactNode) => ReactNode)>) => (string | ReactElement<unknown, string | import("react").JSXElementConstructor<any>>)[];
|
|
20
|
-
export declare const rifmDateProps:
|
|
20
|
+
export declare const rifmDateProps: RifmProps;
|
|
21
21
|
export {};
|
package/README.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# @swan-io/shared-business
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Future, Result } from "@swan-io/boxed";
|
|
2
|
-
import { isNotNullish } from "@swan-io/lake/src/utils/nullish";
|
|
3
|
-
export const queryCompanies = (_query) => Future.make(resolve => {
|
|
4
|
-
const xhr = new XMLHttpRequest();
|
|
5
|
-
xhr.responseType = "json";
|
|
6
|
-
// const params = new URLSearchParams({
|
|
7
|
-
// cibles: "nom_entreprise,denomination,siren",
|
|
8
|
-
// q: query,
|
|
9
|
-
// });
|
|
10
|
-
// xhr.open("GET", `${__SWAN_ENV_PAPPERS_API_URL__}?${params.toString()}`, true);
|
|
11
|
-
xhr.addEventListener("load", () => {
|
|
12
|
-
resolve((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304
|
|
13
|
-
? Result.Ok(xhr.response)
|
|
14
|
-
: Result.Error(new Error(xhr.statusText)));
|
|
15
|
-
});
|
|
16
|
-
xhr.addEventListener("error", () => {
|
|
17
|
-
resolve(Result.Error(new Error("Failed to fetch companies")));
|
|
18
|
-
});
|
|
19
|
-
const timeoutId = setTimeout(() => xhr.send(), 250);
|
|
20
|
-
return () => {
|
|
21
|
-
xhr.abort();
|
|
22
|
-
clearTimeout(timeoutId);
|
|
23
|
-
};
|
|
24
|
-
}).mapOk(({ resultats_siren = [], resultats_nom_entreprise = [], resultats_denomination = [] }) => {
|
|
25
|
-
return [...resultats_siren, ...resultats_nom_entreprise, ...resultats_denomination]
|
|
26
|
-
.filter(isNotNullish)
|
|
27
|
-
.reduce((acc, result) => {
|
|
28
|
-
const { denomination, nom_entreprise, siege, siren = "" } = result;
|
|
29
|
-
const name = nom_entreprise ?? denomination ?? "";
|
|
30
|
-
const city = [siege?.code_postal, siege?.ville].filter(isNotNullish).join(" ");
|
|
31
|
-
// we don't display result without name, without siren or already displayed
|
|
32
|
-
return name === "" || siren === "" || acc.some(suggestion => suggestion.siren === siren)
|
|
33
|
-
? acc
|
|
34
|
-
: [...acc, { value: siren, siren, name, city }];
|
|
35
|
-
}, []);
|
|
36
|
-
}, true);
|