@swan-io/shared-business 8.13.1 → 8.14.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-io/shared-business",
3
- "version": "8.13.1",
3
+ "version": "8.14.0",
4
4
  "engines": {
5
5
  "node": ">=20.9.0",
6
6
  "yarn": "^1.22.0"
@@ -0,0 +1,10 @@
1
+ import { ExtractedDate } from "../utils/date";
2
+ export type InlineDatePickerProps = {
3
+ label: string;
4
+ value: ExtractedDate | undefined;
5
+ onValueChange: (value: ExtractedDate) => void;
6
+ error?: string;
7
+ onBlur?: () => void;
8
+ order: "day-month-year" | "month-day-year";
9
+ };
10
+ export declare const InlineDatePicker: ({ value, label, onValueChange, error, onBlur, order, }: InlineDatePickerProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from "@swan-io/lake/src/components/Box";
3
+ import { InputError } from "@swan-io/lake/src/components/InputError";
4
+ import { LakeLabel } from "@swan-io/lake/src/components/LakeLabel";
5
+ import { LakeSelect } from "@swan-io/lake/src/components/LakeSelect";
6
+ import { LakeTextInput } from "@swan-io/lake/src/components/LakeTextInput";
7
+ import { Stack } from "@swan-io/lake/src/components/Stack";
8
+ import { colors } from "@swan-io/lake/src/constants/design";
9
+ import { isNotNullish } from "@swan-io/lake/src/utils/nullish";
10
+ import { StyleSheet, View } from "react-native";
11
+ import { t } from "../utils/i18n";
12
+ const months = [
13
+ { value: "01", name: t("datePicker.month.january") },
14
+ { value: "02", name: t("datePicker.month.february") },
15
+ { value: "03", name: t("datePicker.month.march") },
16
+ { value: "04", name: t("datePicker.month.april") },
17
+ { value: "05", name: t("datePicker.month.may") },
18
+ { value: "06", name: t("datePicker.month.june") },
19
+ { value: "07", name: t("datePicker.month.july") },
20
+ { value: "08", name: t("datePicker.month.august") },
21
+ { value: "09", name: t("datePicker.month.september") },
22
+ { value: "10", name: t("datePicker.month.october") },
23
+ { value: "11", name: t("datePicker.month.november") },
24
+ { value: "12", name: t("datePicker.month.december") },
25
+ ];
26
+ const styles = StyleSheet.create({
27
+ day: {
28
+ maxWidth: 90,
29
+ flexGrow: 0,
30
+ },
31
+ year: {
32
+ maxWidth: 120,
33
+ flexGrow: 0,
34
+ },
35
+ error: {
36
+ borderColor: colors.negative[400],
37
+ },
38
+ });
39
+ export const InlineDatePicker = ({ value = { day: "", month: "", year: "" }, label, onValueChange, error, onBlur, order, }) => {
40
+ return (_jsx(LakeLabel, { label: label, render: id => {
41
+ const day = (_jsx(View, { style: styles.day, children: _jsx(LakeTextInput, { id: id, style: isNotNullish(error) && styles.error, placeholder: t("datePicker.day"), value: value.day, onBlur: onBlur, hideErrors: true, onChangeText: day => {
42
+ onValueChange({
43
+ day,
44
+ month: value.month,
45
+ year: value.year,
46
+ });
47
+ }, pattern: "[0-9]", maxLength: 2, autoComplete: "bday-day" }) }));
48
+ const month = (_jsx(LakeSelect, { value: value.month === "" ? undefined : value.month, style: isNotNullish(error) && styles.error, placeholder: t("datePicker.month"), hideErrors: true, items: months, onValueChange: month => {
49
+ onValueChange({
50
+ day: value.day,
51
+ month,
52
+ year: value.year,
53
+ });
54
+ } }));
55
+ const year = (_jsx(View, { style: styles.year, children: _jsx(LakeTextInput, { value: value.year, style: isNotNullish(error) && styles.error, placeholder: t("datePicker.year"), onBlur: onBlur, hideErrors: true, onChangeText: year => onValueChange({
56
+ day: value.day,
57
+ month: value.month,
58
+ year,
59
+ }), pattern: "[0-9]", maxLength: 4, autoComplete: "bday-year" }) }));
60
+ return (_jsxs(Box, { children: [order === "day-month-year" ? (_jsxs(Stack, { direction: "row", space: 12, children: [day, " ", month, " ", year] })) : (_jsxs(Stack, { direction: "row", space: 12, children: [month, " ", day, " ", year] })), _jsx(InputError, { message: error })] }));
61
+ } }));
62
+ };
@@ -40,6 +40,7 @@
40
40
  "common.skipToContent": "Skip to content",
41
41
  "copyButton.copiedTooltip": "Copied to clipboard",
42
42
  "copyButton.copyTooltip": "Click to copy",
43
+ "datePicker.day": "Day",
43
44
  "datePicker.day.friday": "Friday",
44
45
  "datePicker.day.monday": "Monday",
45
46
  "datePicker.day.saturday": "Saturday",
@@ -47,6 +48,7 @@
47
48
  "datePicker.day.thursday": "Thursday",
48
49
  "datePicker.day.tuesday": "Tuesday",
49
50
  "datePicker.day.wednesday": "Wednesday",
51
+ "datePicker.month": "Month",
50
52
  "datePicker.month.april": "April",
51
53
  "datePicker.month.august": "August",
52
54
  "datePicker.month.december": "December",
@@ -61,6 +63,7 @@
61
63
  "datePicker.month.october": "October",
62
64
  "datePicker.month.previous": "Previous month",
63
65
  "datePicker.month.september": "September",
66
+ "datePicker.year": "Year",
64
67
  "error.generic": "An error occurred",
65
68
  "error.iban.invalid": "This IBAN doesn't look right. Trying entering it again.",
66
69
  "error.network.500": "Internal server error",
@@ -293,5 +296,7 @@
293
296
  "transactionStatement.title.creditor": "Creditor information",
294
297
  "transactionStatement.title.debtor": "Debtor information",
295
298
  "transactionStatement.title.document": "Transaction confirmation",
296
- "transactionStatement.title.information": "Information"
299
+ "transactionStatement.title.information": "Information",
300
+ "validation.invalidBirthDate": "Invalid birthdate",
301
+ "validation.birthdateCannotBeFuture": "Birthdate cannot be in the future"
297
302
  }
@@ -1,2 +1,9 @@
1
1
  export declare const decodeBirthDate: (value: string) => string;
2
2
  export declare const encodeBirthDate: (value: string) => string;
3
+ export type ExtractedDate = {
4
+ day: string;
5
+ month: string;
6
+ year: string;
7
+ };
8
+ export declare const extractDate: (value: string) => ExtractedDate | undefined;
9
+ export declare const formatExtractedDate: (date: ExtractedDate) => string;
package/src/utils/date.js CHANGED
@@ -1,9 +1,25 @@
1
1
  import dayjs from "dayjs";
2
2
  export const decodeBirthDate = (value) => {
3
- const date = dayjs.utc(value, "YYYY-MM-DD");
3
+ const date = dayjs.utc(value, "YYYY-MM-DD", true);
4
4
  return date.isValid() ? date.format("DD/MM/YYYY") : "";
5
5
  };
6
6
  export const encodeBirthDate = (value) => {
7
- const date = dayjs.utc(value, "DD/MM/YYYY");
7
+ const date = dayjs.utc(value, "DD/MM/YYYY", true);
8
8
  return date.isValid() ? date.format("YYYY-MM-DD") : "";
9
9
  };
10
+ export const extractDate = (value) => {
11
+ const date = dayjs.utc(value, "YYYY-MM-DD", true);
12
+ if (date.isValid()) {
13
+ return {
14
+ day: date.format("DD"),
15
+ month: date.format("MM"),
16
+ year: date.format("YYYY"),
17
+ };
18
+ }
19
+ };
20
+ export const formatExtractedDate = (date) => {
21
+ const day = date.day.trim().padStart(2, "0");
22
+ const month = date.month.trim().padStart(2, "0");
23
+ const year = date.year.trim().padStart(4, "0");
24
+ return `${year}-${month}-${day}`;
25
+ };
@@ -1,4 +1,5 @@
1
1
  import { Validator } from "@swan-io/use-form";
2
+ import { ExtractedDate } from "./date";
2
3
  import { AccountCountry } from "./templateTranslations";
3
4
  export declare const isValidVatNumber: (maybeVat: string) => boolean;
4
5
  export declare const isValidEmail: (maybeEmail: string) => boolean;
@@ -9,3 +10,4 @@ export declare const validateIndividualTaxNumber: (accountCountry: AccountCountr
9
10
  export declare const validateCompanyTaxNumber: (accountCountry: AccountCountry) => Validator<string | undefined>;
10
11
  export { printFormat as printIbanFormat } from "iban";
11
12
  export declare const validateIban: (iban: string) => string | undefined;
13
+ export declare const validateBirthdate: (value: ExtractedDate) => string | undefined;
@@ -1,6 +1,8 @@
1
1
  import { noop } from "@swan-io/lake/src/utils/function";
2
+ import dayjs from "dayjs";
2
3
  import { isValid as isValidIban } from "iban";
3
4
  import { match } from "ts-pattern";
5
+ import { formatExtractedDate } from "./date";
4
6
  import { t } from "./i18n";
5
7
  const EMAIL_REGEX = /^[A-Z0-9_+.-]*[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\.)+[A-Z]{2,}$/i;
6
8
  const VAT_NUMBER_REGEX = /^((AT)?U[0-9]{8}|(BE)?0[0-9]{9}|(BG)?[0-9]{9,10}|(CY)?[0-9]{8}L|(CZ)?[0-9]{8,10}|(DE)?[0-9]{9}|(DK)?[0-9]{8}|(EE)?[0-9]{9}|(EL|GR)?[0-9]{9}|(ES)?[0-9A-Z][0-9]{7}[0-9A-Z]|(FI)?[0-9]{8}|(FR)?[0-9A-Z]{2}[0-9]{9}|(GB)?([0-9]{9}([0-9]{3})?|[A-Z]{2}[0-9]{3})|(HU)?[0-9]{8}|(IE)?[0-9]S[0-9]{5}L|(IT)?[0-9]{11}|(LT)?([0-9]{9}|[0-9]{12})|(LU)?[0-9]{8}|(LV)?[0-9]{11}|(MT)?[0-9]{8}|(NL)?[0-9]{9}B[0-9]{2}|(PL)?[0-9]{10}|(PT)?[0-9]{9}|(RO)?[0-9]{2,10}|(SE)?[0-9]{12}|(SI)?[0-9]{8}|(SK)?[0-9]{10})$/;
@@ -102,3 +104,14 @@ export const validateIban = (iban) => {
102
104
  return t("error.iban.invalid");
103
105
  }
104
106
  };
107
+ export const validateBirthdate = (value) => {
108
+ const date = dayjs.utc(formatExtractedDate(value), "YYYY-MM-DD", true);
109
+ const isBirthdateOver150years = date.isBefore(dayjs.utc().subtract(150, "years"));
110
+ const isBirthdateWithin4years = date.isAfter(dayjs.utc().subtract(4, "years"));
111
+ if (!date.isValid() || isBirthdateOver150years || isBirthdateWithin4years) {
112
+ return t("validation.invalidBirthDate");
113
+ }
114
+ if (date.isAfter(dayjs.utc().add(1, "day"))) {
115
+ return t("validation.birthdateCannotBeFuture");
116
+ }
117
+ };