Compare commits
6
Commits
d4d5edecec
..
v1.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df86b8450f | ||
|
|
b5ceb77208 | ||
|
|
b009101b7b | ||
|
|
7e6fd95cfa | ||
|
|
2cd6b1e72d | ||
|
|
3af9df0ae2 |
@@ -1,5 +1,19 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.2.1](https://git.personal.ksv741.ru/WealthLedger/frontend/compare/v1.2.0...v1.2.1) (2026-10-24)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* keep session when refresh fails on network error or 5xx (WealthLedger/frontend[#97](https://git.personal.ksv741.ru/WealthLedger/frontend/issues/97)) ([3af9df0](https://git.personal.ksv741.ru/WealthLedger/frontend/commit/3af9df0ae2f0fb314c276504ef7d50a7472de680))
|
||||||
|
* show snapshot time in browser time zone ([#101](https://git.personal.ksv741.ru/WealthLedger/frontend/issues/101)) ([b009101](https://git.personal.ksv741.ru/WealthLedger/frontend/commit/b009101b7b954e8462672a9da859267ebb71edc4))
|
||||||
|
|
||||||
|
### Maintenance
|
||||||
|
|
||||||
|
* bump Node to 24.22.1 (WealthLedger/backend[#122](https://git.personal.ksv741.ru/WealthLedger/frontend/issues/122)) ([2cd6b1e](https://git.personal.ksv741.ru/WealthLedger/frontend/commit/2cd6b1e72d97117b0c37465aac3d989b0469c1c3))
|
||||||
|
* bump test stack and fix npm audit findings ([#105](https://git.personal.ksv741.ru/WealthLedger/frontend/issues/105)) ([7e6fd95](https://git.personal.ksv741.ru/WealthLedger/frontend/commit/7e6fd95cfaf7d288242fb46ec7091f561e6f3de5))
|
||||||
|
* **deps:** update non-major dependencies [#9](https://git.personal.ksv741.ru/WealthLedger/frontend/issues/9) ([b5ceb77](https://git.personal.ksv741.ru/WealthLedger/frontend/commit/b5ceb77208e35a0e389258f3d3c4b85852980042))
|
||||||
|
* resolve dev dependency audit findings (WealthLedger/frontend[#103](https://git.personal.ksv741.ru/WealthLedger/frontend/issues/103)) ([7b6f34c](https://git.personal.ksv741.ru/WealthLedger/frontend/commit/7b6f34c776fa3517c93b5c3468e3b277aaa6273f))
|
||||||
|
|
||||||
## [1.2.0](https://git.personal.ksv741.ru/WealthLedger/frontend/compare/v1.1.0...v1.2.0) (2026-10-18)
|
## [1.2.0](https://git.personal.ksv741.ru/WealthLedger/frontend/compare/v1.1.0...v1.2.0) (2026-10-18)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24.21.0-bookworm-slim AS dependencies
|
FROM node:24.22.1-bookworm-slim AS dependencies
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV HUSKY=0
|
ENV HUSKY=0
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
@@ -19,7 +19,7 @@ COPY . .
|
|||||||
ENV VITE_API_BASE_URL=""
|
ENV VITE_API_BASE_URL=""
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM nginx:1.28.0-alpine AS production
|
FROM nginx:1.31.8-alpine AS production
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
ARG REVISION
|
ARG REVISION
|
||||||
LABEL org.opencontainers.image.version=$VERSION \
|
LABEL org.opencontainers.image.version=$VERSION \
|
||||||
|
|||||||
Generated
+1003
-1138
File diff suppressed because it is too large
Load Diff
+46
-44
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "wealth-ledger-frontend",
|
"name": "wealth-ledger-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "24.21.0"
|
"node": "24.22.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npm run build:packages && vite",
|
"dev": "npm run build:packages && vite",
|
||||||
@@ -37,88 +37,90 @@
|
|||||||
"*.{js,mjs,cjs,ts,tsx}": "eslint --fix --max-warnings=0 --no-warn-ignored"
|
"*.{js,mjs,cjs,ts,tsx}": "eslint --fix --max-warnings=0 --no-warn-ignored"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "5.9.1",
|
"@hookform/resolvers": "5.9.2",
|
||||||
"@mantine/charts": "9.6.1",
|
"@mantine/charts": "9.7.3",
|
||||||
"@mantine/core": "9.6.1",
|
"@mantine/core": "9.7.3",
|
||||||
"@mantine/dates": "9.6.1",
|
"@mantine/dates": "9.7.3",
|
||||||
"@mantine/hooks": "9.6.1",
|
"@mantine/hooks": "9.7.3",
|
||||||
"@mantine/notifications": "9.6.1",
|
"@mantine/notifications": "9.7.3",
|
||||||
"@tanstack/react-query": "5.102.8",
|
"@tanstack/react-query": "5.104.5",
|
||||||
"@wealthledger/icons": "file:packages/icons",
|
"@wealthledger/icons": "file:packages/icons",
|
||||||
"@wealthledger/tokens": "file:packages/tokens",
|
"@wealthledger/tokens": "file:packages/tokens",
|
||||||
"@wealthledger/ui": "file:packages/ui",
|
"@wealthledger/ui": "file:packages/ui",
|
||||||
"dayjs": "1.11.23",
|
"dayjs": "1.11.23",
|
||||||
"i18next": "26.4.2",
|
"i18next": "26.5.10",
|
||||||
"motion": "13.2.0",
|
"motion": "13.5.1",
|
||||||
"openapi-fetch": "0.17.0",
|
"openapi-fetch": "0.17.0",
|
||||||
"openapi-react-query": "0.5.4",
|
"openapi-react-query": "0.5.4",
|
||||||
"react": "19.3.0",
|
"react": "19.3.1",
|
||||||
"react-dom": "19.3.0",
|
"react-dom": "19.3.1",
|
||||||
"react-hook-form": "7.88.0",
|
"react-hook-form": "7.91.0",
|
||||||
"react-i18next": "17.0.14",
|
"react-i18next": "17.1.8",
|
||||||
"react-is": "19.3.0",
|
"react-is": "19.3.1",
|
||||||
"react-router": "8.3.1",
|
"react-router": "8.5.0",
|
||||||
"recharts": "3.10.1",
|
"recharts": "3.10.1",
|
||||||
"zod": "4.6.4"
|
"zod": "4.6.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "8.0.5",
|
"@babel/core": "8.0.9",
|
||||||
"@commitlint/cli": "21.2.2",
|
"@commitlint/cli": "21.2.4",
|
||||||
"@commitlint/config-conventional": "21.2.2",
|
"@commitlint/config-conventional": "21.2.4",
|
||||||
"@eslint-react/eslint-plugin": "5.21.0",
|
"@eslint-react/eslint-plugin": "5.28.8",
|
||||||
"@eslint/js": "10.0.1",
|
"@eslint/js": "10.0.1",
|
||||||
"@release-it/conventional-changelog": "12.0.0",
|
"@release-it/conventional-changelog": "12.0.2",
|
||||||
"@rolldown/plugin-babel": "0.2.4",
|
"@rolldown/plugin-babel": "0.2.4",
|
||||||
"@storybook/addon-docs": "10.6.0",
|
"@storybook/addon-docs": "10.6.3",
|
||||||
"@storybook/react-vite": "10.6.0",
|
"@storybook/react-vite": "10.6.3",
|
||||||
"@stylistic/eslint-plugin": "5.10.0",
|
"@stylistic/eslint-plugin": "5.10.0",
|
||||||
"@tanstack/eslint-plugin-query": "5.104.0",
|
"@tanstack/eslint-plugin-query": "5.104.5",
|
||||||
"@testing-library/jest-dom": "7.0.1",
|
"@testing-library/jest-dom": "7.0.1",
|
||||||
"@testing-library/react": "16.3.3",
|
"@testing-library/react": "16.3.3",
|
||||||
"@types/node": "24.13.4",
|
"@types/node": "24.19.2",
|
||||||
"@types/react": "19.3.0",
|
"@types/react": "19.3.0",
|
||||||
"@types/react-dom": "19.3.0",
|
"@types/react-dom": "19.3.0",
|
||||||
"@vitejs/plugin-react": "6.1.1",
|
"@vitejs/plugin-react": "6.1.2",
|
||||||
|
"@vitest/browser": "5.0.5",
|
||||||
"@vitest/browser-playwright": "5.0.5",
|
"@vitest/browser-playwright": "5.0.5",
|
||||||
"@vitest/coverage-v8": "5.0.5",
|
"@vitest/coverage-v8": "5.0.5",
|
||||||
"@vitest/eslint-plugin": "1.6.27",
|
"@vitest/eslint-plugin": "1.6.27",
|
||||||
|
"@vitest/ui": "5.0.5",
|
||||||
"babel-plugin-react-compiler": "1.0.0",
|
"babel-plugin-react-compiler": "1.0.0",
|
||||||
"conventional-changelog-conventionalcommits": "10.4.0",
|
"conventional-changelog-conventionalcommits": "10.4.1",
|
||||||
"dependency-cruiser": "18.2.0",
|
"dependency-cruiser": "18.7.0",
|
||||||
"eslint": "10.11.0",
|
"eslint": "10.13.0",
|
||||||
"eslint-import-resolver-typescript": "4.4.5",
|
"eslint-import-resolver-typescript": "4.4.5",
|
||||||
"eslint-plugin-import-x": "4.17.1",
|
"eslint-plugin-import-x": "4.17.1",
|
||||||
"eslint-plugin-jest-dom": "5.10.1",
|
"eslint-plugin-jest-dom": "5.10.1",
|
||||||
"eslint-plugin-no-unsanitized": "4.1.5",
|
"eslint-plugin-no-unsanitized": "4.1.5",
|
||||||
"eslint-plugin-perfectionist": "5.12.1",
|
"eslint-plugin-perfectionist": "5.13.0",
|
||||||
"eslint-plugin-react-hooks": "7.1.1",
|
"eslint-plugin-react-hooks": "7.1.1",
|
||||||
"eslint-plugin-react-refresh": "0.5.7",
|
"eslint-plugin-react-refresh": "0.5.7",
|
||||||
"eslint-plugin-regexp": "3.3.1",
|
"eslint-plugin-regexp": "3.3.1",
|
||||||
"eslint-plugin-security": "4.1.0",
|
"eslint-plugin-security": "4.2.0",
|
||||||
"eslint-plugin-sonarjs": "4.2.1",
|
"eslint-plugin-sonarjs": "4.2.2",
|
||||||
"eslint-plugin-storybook": "10.6.0",
|
"eslint-plugin-storybook": "10.6.3",
|
||||||
"eslint-plugin-testing-library": "7.16.2",
|
"eslint-plugin-testing-library": "7.16.2",
|
||||||
"eslint-plugin-unicorn": "76.0.0",
|
"eslint-plugin-unicorn": "76.0.0",
|
||||||
"globals": "17.12.0",
|
"globals": "17.13.0",
|
||||||
"husky": "9.1.7",
|
"husky": "9.1.7",
|
||||||
"jsdom": "30.0.1",
|
"jsdom": "30.1.3",
|
||||||
"knip": "6.35.1",
|
"knip": "6.43.0",
|
||||||
"lint-staged": "17.5.1",
|
"lint-staged": "17.6.0",
|
||||||
"msw": "2.15.0",
|
"msw": "2.15.0",
|
||||||
"openapi-typescript": "7.13.0",
|
"openapi-typescript": "7.13.0",
|
||||||
"playwright": "1.63.0",
|
"playwright": "1.64.1",
|
||||||
"release-it": "21.0.2",
|
"release-it": "21.1.1",
|
||||||
"storybook": "10.6.3",
|
"storybook": "10.6.3",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
"typescript-eslint": "8.70.1",
|
"typescript-eslint": "8.72.0",
|
||||||
"vite": "8.3.5",
|
"vite": "8.3.5",
|
||||||
"vite-plugin-pwa": "1.3.0",
|
"vite-plugin-pwa": "1.3.0",
|
||||||
"vitest": "5.0.5"
|
"vitest": "5.0.5"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"release-it": {
|
"release-it": {
|
||||||
"basic-ftp": "6.2.1",
|
"basic-ftp": "6.2.3",
|
||||||
"undici": "7.29.1"
|
"undici": "8.12.3"
|
||||||
},
|
},
|
||||||
"@vitest/browser": "5.0.5",
|
"@vitest/browser": "5.0.5",
|
||||||
"@vitest/ui": "5.0.5",
|
"@vitest/ui": "5.0.5",
|
||||||
|
|||||||
@@ -20,10 +20,10 @@
|
|||||||
"build": "vite build && tsc -p tsconfig.json"
|
"build": "vite build && tsc -p tsconfig.json"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "19.3.0"
|
"react": "19.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/react-vite": "10.6.0",
|
"@storybook/react-vite": "10.6.3",
|
||||||
"@testing-library/react": "16.3.3",
|
"@testing-library/react": "16.3.3",
|
||||||
"@types/react": "19.3.0",
|
"@types/react": "19.3.0",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
|
|||||||
@@ -27,13 +27,13 @@
|
|||||||
"@wealthledger/tokens": "0.3.0"
|
"@wealthledger/tokens": "0.3.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@mantine/core": "9.6.1",
|
"@mantine/core": "9.7.3",
|
||||||
"@mantine/hooks": "9.6.1",
|
"@mantine/hooks": "9.7.3",
|
||||||
"react": "19.3.0",
|
"react": "19.3.1",
|
||||||
"react-dom": "19.3.0"
|
"react-dom": "19.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/react-vite": "10.6.0",
|
"@storybook/react-vite": "10.6.3",
|
||||||
"@testing-library/react": "16.3.3",
|
"@testing-library/react": "16.3.3",
|
||||||
"@types/react": "19.3.0",
|
"@types/react": "19.3.0",
|
||||||
"storybook": "10.6.3",
|
"storybook": "10.6.3",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { useAuth } from "@/features/auth";
|
|||||||
|
|
||||||
type BoundaryProps = PropsWithChildren<{
|
type BoundaryProps = PropsWithChildren<{
|
||||||
authenticated: boolean;
|
authenticated: boolean;
|
||||||
routeKey: string;
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type RouteErrorFallbackProps = {
|
type RouteErrorFallbackProps = {
|
||||||
@@ -26,12 +25,6 @@ class Boundary extends Component<BoundaryProps, State> {
|
|||||||
|
|
||||||
override state: State = { hasError: false };
|
override state: State = { hasError: false };
|
||||||
|
|
||||||
override componentDidUpdate(previousProps: BoundaryProps) {
|
|
||||||
if (previousProps.routeKey !== this.props.routeKey && this.state.hasError) {
|
|
||||||
this.setState({ hasError: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
return this.state.hasError
|
return this.state.hasError
|
||||||
? <RouteErrorFallback authenticated={this.props.authenticated} />
|
? <RouteErrorFallback authenticated={this.props.authenticated} />
|
||||||
@@ -70,10 +63,7 @@ const RouteErrorBoundary: FC<PropsWithChildren> = (props) => {
|
|||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Boundary
|
<Boundary authenticated={Boolean(user)} key={`${pathname}${search}:${key}`}>
|
||||||
authenticated={Boolean(user)}
|
|
||||||
routeKey={`${pathname}${search}:${key}`}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</Boundary>
|
</Boundary>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ function renderEvents(accountId: string, searches: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("Upcoming event date filters", () => {
|
describe("Upcoming event date filters", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
vi.useRealTimers();
|
||||||
|
});
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Pin "today": the test picks today + 10 days, which must be inside the visible calendar grid.
|
// Pin "today": the test picks today + 10 days, which must be inside the visible calendar grid.
|
||||||
// Real dates can push it beyond the grid (e.g. 2026-10-23 -> 2 November).
|
// Real dates can push it beyond the grid (e.g. 2026-10-23 -> 2 November).
|
||||||
@@ -235,6 +238,10 @@ describe("Upcoming event date filters", () => {
|
|||||||
it.each(["account-1", "all"])(
|
it.each(["account-1", "all"])(
|
||||||
"applies dates only on submit, restores URL dates, and resets from empty results for %s",
|
"applies dates only on submit, restores URL dates, and resets from empty results for %s",
|
||||||
async (accountId) => {
|
async (accountId) => {
|
||||||
|
// Pin "today" mid-month so "today + 10 days" stays in the calendar's
|
||||||
|
// visible month regardless of the real date.
|
||||||
|
vi.useFakeTimers({ toFake: ["Date"] });
|
||||||
|
vi.setSystemTime(new Date("2026-10-15T12:00:00+03:00"));
|
||||||
const [defaultFrom, defaultTo] = defaultPeriod();
|
const [defaultFrom, defaultTo] = defaultPeriod();
|
||||||
const searches: string[] = [];
|
const searches: string[] = [];
|
||||||
server.use(
|
server.use(
|
||||||
|
|||||||
@@ -413,7 +413,9 @@ describe("stock page", () => {
|
|||||||
expect(await screen.findByText("Продажа")).toBeVisible();
|
expect(await screen.findByText("Продажа")).toBeVisible();
|
||||||
expect(screen.getByText("2 шт.")).toBeVisible();
|
expect(screen.getByText("2 шт.")).toBeVisible();
|
||||||
expect(screen.getByText("Цена: 100 ₽")).toBeVisible();
|
expect(screen.getByText("Цена: 100 ₽")).toBeVisible();
|
||||||
expect(screen.getByText(/02.01.2022, 10:00 UTC/)).toBeVisible();
|
const snapshotTime = new Intl.DateTimeFormat("ru-RU", { dateStyle: "short", timeStyle: "short" });
|
||||||
|
const operationTime = snapshotTime.format(new Date("2022-01-02T10:00:00Z"));
|
||||||
|
expect(screen.getByText(operationTime, { exact: false })).toBeVisible();
|
||||||
expect(
|
expect(
|
||||||
requests.some(
|
requests.some(
|
||||||
url =>
|
url =>
|
||||||
|
|||||||
@@ -93,7 +93,9 @@ describe("stock search", () => {
|
|||||||
expect(
|
expect(
|
||||||
await screen.findByRole("link", { name: /Сбербанк/ }),
|
await screen.findByRole("link", { name: /Сбербанк/ }),
|
||||||
).toHaveAttribute("href", "/stocks/e6123145-9665-43e0-8413-cd61b8aa9b13");
|
).toHaveAttribute("href", "/stocks/e6123145-9665-43e0-8413-cd61b8aa9b13");
|
||||||
expect(screen.getByText("Список получен 10.10.2026, 10:00")).toBeVisible();
|
const snapshotTime = new Intl.DateTimeFormat("ru-RU", { dateStyle: "short", timeStyle: "short" });
|
||||||
|
const fetchedAt = snapshotTime.format(new Date("2026-10-10T10:00:00Z"));
|
||||||
|
expect(screen.getByText(`Список получен ${fetchedAt}`)).toBeVisible();
|
||||||
expect(screen.getByText("Лот: 10 шт.")).toBeVisible();
|
expect(screen.getByText("Лот: 10 шт.")).toBeVisible();
|
||||||
expect(screen.getByText("ISIN: RU0009029540")).toBeVisible();
|
expect(screen.getByText("ISIN: RU0009029540")).toBeVisible();
|
||||||
expect(screen.getAllByText("Мосбиржа")[0]).toBeVisible();
|
expect(screen.getAllByText("Мосбиржа")[0]).toBeVisible();
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ const ru = {
|
|||||||
next: "Далее",
|
next: "Далее",
|
||||||
noInstrument: "Без инструмента",
|
noInstrument: "Без инструмента",
|
||||||
noMoney: "Без движения денег",
|
noMoney: "Без движения денег",
|
||||||
occurredAt: "{{date}} UTC",
|
occurredAt: "{{date}}",
|
||||||
open: "Открыть журнал",
|
open: "Открыть журнал",
|
||||||
operationType: {
|
operationType: {
|
||||||
buy: "Покупка",
|
buy: "Покупка",
|
||||||
@@ -632,7 +632,7 @@ const ru = {
|
|||||||
position: "Моя позиция",
|
position: "Моя позиция",
|
||||||
previous: "Назад",
|
previous: "Назад",
|
||||||
price: "Цена",
|
price: "Цена",
|
||||||
priceAt: "Цена на {{date}} UTC",
|
priceAt: "Цена на {{date}}",
|
||||||
priceTable: "Цены в таблице",
|
priceTable: "Цены в таблице",
|
||||||
priceTableHint: "Дневные закрытия · записей: {{count}} · сначала новые",
|
priceTableHint: "Дневные закрытия · записей: {{count}} · сначала новые",
|
||||||
priceUnavailable: "Цена недоступна",
|
priceUnavailable: "Цена недоступна",
|
||||||
@@ -721,7 +721,7 @@ const ru = {
|
|||||||
SHARE_TYPE_GDR: "Депозитарная расписка",
|
SHARE_TYPE_GDR: "Депозитарная расписка",
|
||||||
SHARE_TYPE_PREFERRED: "Привилегированная акция",
|
SHARE_TYPE_PREFERRED: "Привилегированная акция",
|
||||||
},
|
},
|
||||||
snapshotAt: "Позиция на {{date}} UTC",
|
snapshotAt: "Позиция на {{date}}",
|
||||||
trading: {
|
trading: {
|
||||||
SECURITY_TRADING_STATUS_BREAK_IN_TRADING: "Перерыв в торгах",
|
SECURITY_TRADING_STATUS_BREAK_IN_TRADING: "Перерыв в торгах",
|
||||||
SECURITY_TRADING_STATUS_CLOSING_AUCTION: "Аукцион закрытия",
|
SECURITY_TRADING_STATUS_CLOSING_AUCTION: "Аукцион закрытия",
|
||||||
|
|||||||
@@ -12,9 +12,16 @@ describe("shared display helpers", () => {
|
|||||||
expect(formatDate("2027-09-10")).toBe("10.09.2027");
|
expect(formatDate("2027-09-10")).toBe("10.09.2027");
|
||||||
expect(formatDate("2024-02-29")).toBe("29.02.2024");
|
expect(formatDate("2024-02-29")).toBe("29.02.2024");
|
||||||
expect(formatDate("2027-09-10T00:30:00+03:00")).toBe("09.09.2027");
|
expect(formatDate("2027-09-10T00:30:00+03:00")).toBe("09.09.2027");
|
||||||
expect(formatSnapshotTime("2027-09-10T00:30:00+03:00")).toBe(
|
});
|
||||||
"09.09.2027, 21:30",
|
it("formats snapshot time in the browser time zone", () => {
|
||||||
);
|
const instant = "2027-09-10T00:30:00+03:00";
|
||||||
|
|
||||||
|
const expected = new Intl.DateTimeFormat("ru-RU", {
|
||||||
|
dateStyle: "short",
|
||||||
|
timeStyle: "short",
|
||||||
|
}).format(new Date(instant));
|
||||||
|
|
||||||
|
expect(formatSnapshotTime(instant)).toBe(expected);
|
||||||
});
|
});
|
||||||
it("formats decimal strings without financial arithmetic", () => {
|
it("formats decimal strings without financial arithmetic", () => {
|
||||||
expect(formatMoney({ currency: "RUB", value: "-1234567.89" })).toBe(
|
expect(formatMoney({ currency: "RUB", value: "-1234567.89" })).toBe(
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ function formatMoney(
|
|||||||
return `${formatDecimal(decimal)} ${currency}`;
|
return `${formatDecimal(decimal)} ${currency}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Без timeZone Intl берёт часовой пояс браузера пользователя.
|
||||||
const snapshotFormatter = new Intl.DateTimeFormat("ru-RU", {
|
const snapshotFormatter = new Intl.DateTimeFormat("ru-RU", {
|
||||||
dateStyle: "short",
|
dateStyle: "short",
|
||||||
timeStyle: "short",
|
timeStyle: "short",
|
||||||
timeZone: "UTC",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function formatSnapshotTime(value: string): string {
|
function formatSnapshotTime(value: string): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user