diff --git a/src/components/domains/TrialPayment/Legal/Legal.tsx b/src/components/domains/TrialPayment/Legal/Legal.tsx
index d21ba58..3247bca 100644
--- a/src/components/domains/TrialPayment/Legal/Legal.tsx
+++ b/src/components/domains/TrialPayment/Legal/Legal.tsx
@@ -45,7 +45,7 @@ export default function Legal({
link.className
)}
>
- {link.children}
+ {link.children}
))}
diff --git a/src/components/funnel/templates/DateTemplate/DateTemplate.tsx b/src/components/funnel/templates/DateTemplate/DateTemplate.tsx
index a567150..5356e3a 100644
--- a/src/components/funnel/templates/DateTemplate/DateTemplate.tsx
+++ b/src/components/funnel/templates/DateTemplate/DateTemplate.tsx
@@ -9,18 +9,19 @@ import { TemplateLayout } from "../layouts/TemplateLayout";
import { createTemplateLayoutProps } from "@/lib/funnel/templateHelpers";
// Утилита для форматирования даты на основе паттерна
-function formatDateByPattern(date: Date, pattern: string): string {
+// Принимает год, месяц, день как числа (без зависимости от часовых зон)
+function formatDateByPattern(year: number, month: number, day: number, pattern: string): string {
const monthNames = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
return pattern
- .replace("MMMM", monthNames[date.getMonth()])
- .replace("MMM", monthNames[date.getMonth()].substring(0, 3))
- .replace("yyyy", date.getFullYear().toString())
- .replace("dd", date.getDate().toString().padStart(2, '0'))
- .replace("d", date.getDate().toString());
+ .replace("MMMM", monthNames[month - 1])
+ .replace("MMM", monthNames[month - 1].substring(0, 3))
+ .replace("yyyy", year.toString())
+ .replace("dd", day.toString().padStart(2, '0'))
+ .replace("d", day.toString());
}
interface DateTemplateProps {
@@ -83,12 +84,21 @@ export function DateTemplate({
// Форматированная дата для отображения
const formattedDate = useMemo(() => {
- if (!isoDate) return null;
+ const { month, day, year } = selectedDate;
+ if (!month || !day || !year) return null;
- const date = new Date(isoDate);
- const pattern = screen.dateInput?.selectedDateFormat || "MMMM d, yyyy";
- return formatDateByPattern(date, pattern);
- }, [isoDate, screen.dateInput?.selectedDateFormat]);
+ const monthNum = parseInt(month);
+ const dayNum = parseInt(day);
+ const yearNum = parseInt(year);
+
+ // Валидация даты
+ if (monthNum >= 1 && monthNum <= 12 && dayNum >= 1 && dayNum <= 31 && yearNum > 1900) {
+ const pattern = screen.dateInput?.selectedDateFormat || "MMMM d, yyyy";
+ return formatDateByPattern(yearNum, monthNum, dayNum, pattern);
+ }
+
+ return null;
+ }, [selectedDate, screen.dateInput?.selectedDateFormat]);
// Компонент отображения выбранной даты над кнопкой
const selectedDateDisplay = formattedDate && screen.dateInput?.showSelectedDate !== false ? (
@@ -138,7 +148,6 @@ export function DateTemplate({
onChange={handleDateChange}
maxYear={new Date().getFullYear() - 11}
yearsRange={100}
- locale="en"
/>
{defaultTexts?.privacyBanner && (
diff --git a/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx b/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx
index b074cb6..f387f1c 100644
--- a/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx
+++ b/src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx
@@ -689,8 +689,6 @@ export function TrialPaymentTemplate({
By clicking Continue, you agree to our{" "}
Terms of Use & Service
@@ -698,8 +696,6 @@ export function TrialPaymentTemplate({
and{" "}
Privacy Policy
diff --git a/src/components/templates/QuestionDateAnswers/QuestionDateAnswers.stories.tsx b/src/components/templates/QuestionDateAnswers/QuestionDateAnswers.stories.tsx
index ae2ac58..b6ba595 100644
--- a/src/components/templates/QuestionDateAnswers/QuestionDateAnswers.stories.tsx
+++ b/src/components/templates/QuestionDateAnswers/QuestionDateAnswers.stories.tsx
@@ -34,7 +34,6 @@ const meta: Meta = {
onChange: fn(),
maxYear: new Date().getFullYear() - 11,
yearsRange: 100,
- locale: "en",
},
bottomActionButtonProps: {
actionButtonProps: {
@@ -72,7 +71,6 @@ export const WithInitialValue = {
onChange: fn(),
maxYear: new Date().getFullYear() - 11,
yearsRange: 100,
- locale: "en",
},
},
} satisfies Story;
@@ -84,7 +82,6 @@ export const WithError = {
onChange: fn(),
maxYear: new Date().getFullYear() - 11,
yearsRange: 100,
- locale: "en",
},
},
} satisfies Story;
@@ -96,7 +93,6 @@ export const WithCustomLocale = {
onChange: fn(),
maxYear: new Date().getFullYear() - 11,
yearsRange: 100,
- locale: "ru",
},
},
} satisfies Story;
@@ -108,7 +104,6 @@ export const WithCustomYearRange = {
onChange: fn(),
maxYear: 2000,
yearsRange: 50,
- locale: "en",
},
},
} satisfies Story;
@@ -120,7 +115,6 @@ export const WithoutBottomButton = {
onChange: fn(),
maxYear: new Date().getFullYear() - 11,
yearsRange: 100,
- locale: "en",
},
bottomActionButtonProps: undefined,
},
diff --git a/src/components/widgets/DateInput/DateInput.stories.tsx b/src/components/widgets/DateInput/DateInput.stories.tsx
index bc84af3..e09aef9 100644
--- a/src/components/widgets/DateInput/DateInput.stories.tsx
+++ b/src/components/widgets/DateInput/DateInput.stories.tsx
@@ -27,11 +27,6 @@ const meta: Meta = {
control: { type: "number" },
description: "Диапазон лет для выбора",
},
- locale: {
- control: { type: "select" },
- options: ["en", "ru", "de", "fr"],
- description: "Локаль для отображения месяцев",
- },
error: {
control: { type: "text" },
description: "Сообщение об ошибке",
@@ -74,10 +69,9 @@ export const WithError = {
},
} satisfies Story;
-export const RussianLocale = {
+export const WithEmptyValue = {
args: {
value: null,
- locale: "ru",
},
} satisfies Story;
diff --git a/src/components/widgets/DateInput/DateInput.tsx b/src/components/widgets/DateInput/DateInput.tsx
index 4ee6fee..16366d9 100644
--- a/src/components/widgets/DateInput/DateInput.tsx
+++ b/src/components/widgets/DateInput/DateInput.tsx
@@ -17,7 +17,6 @@ export interface DateInputProps {
maxYear?: number;
yearsRange?: number;
// onBlur?: () => void;
- locale?: string;
daySelectProps?: LocalSelectInputProps;
monthSelectProps?: LocalSelectInputProps;
yearSelectProps?: LocalSelectInputProps;
@@ -30,7 +29,6 @@ export default function DateInput({
maxYear = new Date().getFullYear() - 11,
yearsRange = 100,
// onBlur,
- locale = "en",
daySelectProps,
monthSelectProps,
yearSelectProps,
@@ -51,7 +49,6 @@ export default function DateInput({
onChange,
maxYear,
yearsRange,
- locale,
});
const inputs = {
diff --git a/src/components/widgets/PrivacyTermsConsent/PrivacyTermsConsent.tsx b/src/components/widgets/PrivacyTermsConsent/PrivacyTermsConsent.tsx
index 7e4b9cb..b8ccc7e 100644
--- a/src/components/widgets/PrivacyTermsConsent/PrivacyTermsConsent.tsx
+++ b/src/components/widgets/PrivacyTermsConsent/PrivacyTermsConsent.tsx
@@ -27,13 +27,13 @@ export default function PrivacyTermsConsent({
I agree to the{" "}
{privacyPolicy && (
)}
{", "}
{termsOfUse && (
)}{" "}
and to the use of cookies and tracking technologies, that require your
diff --git a/src/hooks/useDateInput.ts b/src/hooks/useDateInput.ts
index 119eff2..7816955 100644
--- a/src/hooks/useDateInput.ts
+++ b/src/hooks/useDateInput.ts
@@ -1,8 +1,12 @@
import { SelectInputProps } from "@/components/ui/SelectInput/SelectInput";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+// Валидация даты без зависимости от часовых зон
+// Проверяет что дата существует (например, 31 февраля - невалидна)
const isValidDate = (year: number, month: number, day: number) => {
if (!year || !month || !day) return false;
+ // Используем Date в локальной зоне только для валидации
+ // Это безопасно, т.к. мы не сохраняем результат, только проверяем корректность
const date = new Date(year, month - 1, day);
return (
date.getFullYear() === year &&
@@ -25,13 +29,11 @@ const parseDateValue = (
return { year, month, day };
};
-// Упрощенное определение порядка полей даты на основе локали.
-// В реальном приложении здесь лучше использовать данные из next-intl.
-const getDateInputLocaleFormat = (locale: string): ("d" | "m" | "y")[] => {
- const format = new Intl.DateTimeFormat(locale).format(new Date(2001, 1, 3)); // Используем 3/Feb/2001
- if (/^3.*2/.test(format)) return ["d", "m", "y"]; // 3/2/2001 -> d/m/y
- if (/^2.*3/.test(format)) return ["m", "d", "y"]; // 2/3/2001 -> m/d/y
- return ["y", "m", "d"]; // 2001/2/3 -> y/m/d
+// Порядок полей даты: месяц-день-год (американский формат)
+// Этот формат используется для всех локалей чтобы обеспечить единообразие
+const getDateInputLocaleFormat = (): ("d" | "m" | "y")[] => {
+ // Всегда используем американский формат: месяц, день, год
+ return ["m", "d", "y"];
};
interface UseDateInputProps {
@@ -39,7 +41,6 @@ interface UseDateInputProps {
onChange?: (value: string | null) => void;
maxYear?: number;
yearsRange?: number;
- locale?: string;
}
export const useDateInput = ({
@@ -47,7 +48,6 @@ export const useDateInput = ({
onChange,
maxYear = new Date().getFullYear() - 11,
yearsRange = 100,
- locale = "en",
}: UseDateInputProps) => {
const [year, setYear] = useState("");
const [month, setMonth] = useState("");
@@ -125,8 +125,8 @@ export const useDateInput = ({
}, [year, month]);
const localeFormat = useMemo(
- () => getDateInputLocaleFormat(locale),
- [locale]
+ () => getDateInputLocaleFormat(),
+ []
);
const handleYearChange: SelectInputProps["onValueChange"] = useCallback(