@swan-io/shared-business 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@swan-io/shared-business",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "engines": {
5
5
  "node": ">=14.0.0",
6
6
  "yarn": "^1.20.0"
7
7
  },
8
8
  "files": [
9
9
  "LICENSE",
10
+ "src/assets",
10
11
  "src/**/*.js",
11
12
  "src/**/*.d.ts",
12
13
  "README.md"
@@ -22,11 +23,14 @@
22
23
  "not ie <= 11",
23
24
  "safari >= 12"
24
25
  ],
26
+ "license": "MIT",
25
27
  "dependencies": {
26
28
  "@formatjs/intl": "2.6.7",
29
+ "@googlemaps/js-api-loader": "1.15.1",
27
30
  "@swan-io/boxed": "0.12.1",
28
- "@swan-io/lake": "1.0.0",
31
+ "@swan-io/lake": "*",
29
32
  "react": "18.2.0",
33
+ "react-atomic-state": "1.2.7",
30
34
  "react-dom": "18.2.0",
31
35
  "react-native-web": "0.18.12",
32
36
  "react-ux-form": "1.3.0",
@@ -35,6 +39,7 @@
35
39
  "devDependencies": {
36
40
  "@testing-library/react": "13.4.0",
37
41
  "@testing-library/user-event": "14.4.3",
42
+ "@types/google.maps": "3.52.2",
38
43
  "@types/react": "18.0.28",
39
44
  "@types/react-dom": "18.0.11",
40
45
  "@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
- /// <reference types="react" />
2
- import { CountryCCA3 } from "../constants/countries";
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
- onSuggestionRequest: (input: string) => Promise<Suggestion[]>;
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
- ListFooterComponent?: React.ReactNode;
24
+ emptyResultText: string;
25
+ apiKey?: string;
30
26
  };
31
- export declare const AddressSearchInput: ({ id, country, disabled, error, value: initialValue, onValueChange, onSuggestionRequest, onSelectSuggestion, emptyResultText, placeholder, shouldDisplaySuggestions, ListFooterComponent, }: Props) => JSX.Element;
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 { useEffect, useRef, useState } from "react";
6
- import { LakeText } from "@swan-io/lake/src/components/LakeText";
7
- export const AddressSearchInput = ({ id, country, disabled, error, value: initialValue, onValueChange, onSuggestionRequest, onSelectSuggestion, emptyResultText, placeholder, shouldDisplaySuggestions = true, ListFooterComponent, }) => {
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
- Future.fromPromise(onSuggestionRequest(value)).onResolve(resolve);
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, shouldDisplaySuggestions, onSuggestionRequest]);
64
+ }, [country, value, autocomplete, shouldDisplaySuggestions]);
25
65
  useEffect(() => {
26
66
  showTriggerSearchRef.current = true;
27
67
  }, [value]);
28
- if (shouldDisplaySuggestions) {
29
- return (_jsx(LakeCombobox, { nativeID: id, placeholder: placeholder, value: value, items: state, icon: "search-filled", disabled: disabled, error: error, ListFooterComponent: ListFooterComponent, onSelectItem: suggestion => onSelectSuggestion(suggestion), onValueChange: value => {
30
- setValue(value);
31
- onValueChange(value);
32
- }, keyExtractor: item => item.id, emptyResultText: emptyResultText, renderItem: item => (_jsxs(_Fragment, { children: [_jsx(LakeText, { variant: "semibold", children: item.firstLine }), _jsx(LakeText, { variant: "smallRegular", children: item.secondLine })] })) }));
33
- }
34
- return (_jsx(LakeTextInput, { nativeID: id, placeholder: placeholder, value: value, icon: "search-filled", disabled: disabled, error: error, onChangeText: value => {
35
- setValue(value);
36
- onValueChange(value);
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
- typeOfRepresentation?: TypeOfRepresentation;
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, typeOfRepresentation }, externalRef) => {
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: [typeOfRepresentation == null && (_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 => {
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.length === 0 && !isOther ? (_jsxs(_Fragment, { children: [_jsx(Space, { height: 24 }), _jsx(LakeText, { children: t("supportingDoc.noRequiredDocuments") }), _jsx(Space, { height: 24 })] })) : null, typeOfRepresentation === "LegalRepresentative" || 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 => {
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") }) })] })] })) : null] }));
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" | "PNG" | "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;
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" | "PNG" | "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";
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 {};
@@ -2327,6 +2327,8 @@ const companyCountries = [
2327
2327
  "SVK",
2328
2328
  "SVN",
2329
2329
  "BGR",
2330
+ "CYP",
2331
+ "NOR",
2330
2332
  ];
2331
2333
  export const companyCountriesItems = companyCountries
2332
2334
  .map(cca3 => ({
@@ -0,0 +1,8 @@
1
+ /// <reference types="google.maps" />
2
+ import { AsyncData } from "@swan-io/boxed";
3
+ type Props = {
4
+ language?: string;
5
+ apiKey?: string;
6
+ };
7
+ export declare const useGoogleMapSDK: ({ language, apiKey }: Props) => AsyncData<typeof google>;
8
+ 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
+ };
@@ -1,8 +1,8 @@
1
- import { Props } from "@swan-io/lake/src/utils/rifm";
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 = (typeof supportedLanguages)[number];
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: Props;
20
+ export declare const rifmDateProps: RifmProps;
21
21
  export {};
package/README.md DELETED
@@ -1 +0,0 @@
1
- # @swan-io/shared-business
@@ -1,8 +0,0 @@
1
- import { Future, Result } from "@swan-io/boxed";
2
- export type CompanySuggestion = {
3
- city: string;
4
- name: string;
5
- siren: string;
6
- value: string;
7
- };
8
- export declare const queryCompanies: (_query: string) => Future<Result<Array<CompanySuggestion>, Error>>;
@@ -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);