-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Replace moment.js with native Date/Intl APIs #6404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "saleor-dashboard": patch | ||
| --- | ||
|
|
||
| Replace a few moment.js invocations with native browser APIs |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,17 +1,17 @@ | ||||||||||||||||||||||
| // @ts-strict-ignore | ||||||||||||||||||||||
| import moment from "moment"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import { type ExtendedGiftCard, type GiftCardBase } from "./types"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| function isGiftCardExpired<T extends GiftCardBase>(giftCard: T): boolean { | ||||||||||||||||||||||
| if (!giftCard?.expiryDate) { | ||||||||||||||||||||||
| return false; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return moment(giftCard?.expiryDate).isBefore(moment()); | ||||||||||||||||||||||
| return new Date(giftCard.expiryDate) < new Date(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
+8
to
9
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| export function getExtendedGiftCard<T extends GiftCardBase>(giftCard?: T): ExtendedGiftCard<T> { | ||||||||||||||||||||||
| export function getExtendedGiftCard<T extends GiftCardBase>( | ||||||||||||||||||||||
| giftCard?: T, | ||||||||||||||||||||||
|
Comment on lines
+11
to
+12
|
||||||||||||||||||||||
| export function getExtendedGiftCard<T extends GiftCardBase>( | |
| giftCard?: T, | |
| export function getExtendedGiftCard<T extends GiftCardBase>( | |
| giftCard: T, | |
| ): ExtendedGiftCard<T>; | |
| export function getExtendedGiftCard<T extends GiftCardBase>( | |
| giftCard?: T, | |
| ): ExtendedGiftCard<T> | undefined; | |
| export function getExtendedGiftCard<T extends GiftCardBase>( | |
| giftCard?: T, |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -135,7 +135,10 @@ export const GiftCardsListProvider = ({ children, params }: GiftCardsListProvide | |||||||||||||||||||||||
| variables: newQueryVariables, | ||||||||||||||||||||||||
| handleError: handleGiftCardListError, | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| const giftCards = mapEdgesToItems(data?.giftCards)?.map(getExtendedGiftCard) ?? []; | ||||||||||||||||||||||||
| const giftCards = | ||||||||||||||||||||||||
| mapEdgesToItems(data?.giftCards) | ||||||||||||||||||||||||
| ?.map(getExtendedGiftCard) | ||||||||||||||||||||||||
| .filter((g): g is NonNullable<typeof g> => g !== undefined) ?? []; | ||||||||||||||||||||||||
|
Comment on lines
+138
to
+141
|
||||||||||||||||||||||||
| const giftCards = | |
| mapEdgesToItems(data?.giftCards) | |
| ?.map(getExtendedGiftCard) | |
| .filter((g): g is NonNullable<typeof g> => g !== undefined) ?? []; | |
| const mapToExtendedGiftCard = ( | |
| giftCard: Parameters<typeof getExtendedGiftCard>[0], | |
| ): ExtendedGiftCard => getExtendedGiftCard(giftCard) as ExtendedGiftCard; | |
| const giftCards = | |
| mapEdgesToItems(data?.giftCards)?.map(mapToExtendedGiftCard) ?? []; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import type { Meta, StoryObj } from "@storybook/react-vite"; | ||
|
|
||
| import { TaxAppLabel } from "./TaxAppLabel"; | ||
|
|
||
| const meta: Meta<typeof TaxAppLabel> = { | ||
| title: "Taxes/TaxAppLabel", | ||
| component: TaxAppLabel, | ||
| }; | ||
|
|
||
| export default meta; | ||
|
|
||
| type Story = StoryObj<typeof TaxAppLabel>; | ||
|
|
||
| export const WithNameAndDate: Story = { | ||
| args: { | ||
| name: "Avalara", | ||
| logoUrl: undefined, | ||
| created: "2024-01-15T10:30:00Z", | ||
| id: "app-1", | ||
| }, | ||
| }; | ||
|
|
||
| export const WithLogo: Story = { | ||
| args: { | ||
| name: "TaxJar", | ||
| logoUrl: "https://placeholdit.com/128x128/dddddd/999999?text=app", | ||
| created: "2024-06-20T14:00:00Z", | ||
| id: "app-2", | ||
| }, | ||
| }; | ||
|
|
||
| export const WithoutDate: Story = { | ||
| args: { | ||
| name: "Tax App", | ||
| logoUrl: undefined, | ||
| created: null, | ||
| id: "app-3", | ||
| }, | ||
| }; | ||
|
|
||
| export const WithoutName: Story = { | ||
| args: { | ||
| name: null, | ||
| logoUrl: undefined, | ||
| created: "2024-03-10T08:00:00Z", | ||
| id: "app-4", | ||
| }, | ||
| }; | ||
|
|
||
| export const MinimalProps: Story = { | ||
| args: { | ||
| name: null, | ||
| logoUrl: undefined, | ||
| created: null, | ||
| id: "app-5", | ||
| }, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import { render, screen } from "@testing-library/react"; | ||
|
|
||
| import { TaxAppLabel } from "./TaxAppLabel"; | ||
|
|
||
| jest.mock("@dashboard/extensions/components/AppAvatar/AppAvatar", () => ({ | ||
| AppAvatar: () => <div data-testid="app-avatar" />, | ||
| })); | ||
|
|
||
| jest.mock("@dashboard/hooks/useLocale", () => () => ({ | ||
| locale: "en", | ||
| setLocale: () => undefined, | ||
| })); | ||
|
|
||
| describe("TaxAppLabel", () => { | ||
| it("renders locale-formatted date from ISO string", () => { | ||
| // Arrange & Act | ||
| render( | ||
| <TaxAppLabel name="Tax App" logoUrl={undefined} created="2024-06-15T10:30:00Z" id="1" />, | ||
| ); | ||
|
|
||
| // Assert | ||
| const expected = new Intl.DateTimeFormat("en", { | ||
| year: "numeric", | ||
| month: "2-digit", | ||
| day: "2-digit", | ||
| }).format(new Date("2024-06-15T10:30:00Z")); | ||
|
|
||
| expect(screen.getByText(`(${expected})`)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("does not render date when created is null", () => { | ||
| // Arrange & Act | ||
| const { container } = render( | ||
| <TaxAppLabel name="Tax App" logoUrl={undefined} created={null} id="1" />, | ||
| ); | ||
|
|
||
| // Assert | ||
| expect(container.textContent).not.toContain("("); | ||
| }); | ||
|
|
||
| it("renders app name section when name is provided", () => { | ||
| // Arrange & Act | ||
| render(<TaxAppLabel name="Tax App" logoUrl={undefined} created={null} id="1" />); | ||
|
|
||
| // Assert | ||
| expect(screen.getByText(/Use app/)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("does not render name section when name is null", () => { | ||
| // Arrange & Act | ||
| render(<TaxAppLabel name={null} logoUrl={undefined} created="2024-01-01T00:00:00Z" id="1" />); | ||
|
|
||
| // Assert | ||
| expect(screen.queryByText(/Use app/)).not.toBeInTheDocument(); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,6 @@ | ||||||||||||||||||||||||||||||||||
| import { AppAvatar } from "@dashboard/extensions/components/AppAvatar/AppAvatar"; | ||||||||||||||||||||||||||||||||||
| import useLocale from "@dashboard/hooks/useLocale"; | ||||||||||||||||||||||||||||||||||
| import { Box, Text } from "@saleor/macaw-ui-next"; | ||||||||||||||||||||||||||||||||||
| import moment from "moment"; | ||||||||||||||||||||||||||||||||||
| import { FormattedMessage } from "react-intl"; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| interface TaxAppLabelProps { | ||||||||||||||||||||||||||||||||||
|
|
@@ -10,7 +10,18 @@ interface TaxAppLabelProps { | |||||||||||||||||||||||||||||||||
| id: string; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const formatDate = (locale: string, created: string): string => { | ||||||||||||||||||||||||||||||||||
| const dateTimeString = new Intl.DateTimeFormat(locale, { | ||||||||||||||||||||||||||||||||||
| year: "numeric", | ||||||||||||||||||||||||||||||||||
| month: "2-digit", | ||||||||||||||||||||||||||||||||||
| day: "2-digit", | ||||||||||||||||||||||||||||||||||
| }).format(new Date(created)); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+14
to
+18
|
||||||||||||||||||||||||||||||||||
| const dateTimeString = new Intl.DateTimeFormat(locale, { | |
| year: "numeric", | |
| month: "2-digit", | |
| day: "2-digit", | |
| }).format(new Date(created)); | |
| const date = new Date(created); | |
| if (isNaN(date.getTime())) { | |
| return ""; | |
| } | |
| const dateTimeString = new Intl.DateTimeFormat(locale, { | |
| year: "numeric", | |
| month: "2-digit", | |
| day: "2-digit", | |
| }).format(date); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,4 @@ | ||||||||||||||||||
| import { useUser } from "@dashboard/auth/useUser"; | ||||||||||||||||||
| import moment from "moment"; | ||||||||||||||||||
|
|
||||||||||||||||||
| export const useNewUserCheck = () => { | ||||||||||||||||||
| const { user } = useUser(); | ||||||||||||||||||
|
|
@@ -19,18 +18,19 @@ export const useNewUserCheck = () => { | |||||||||||||||||
| }; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| const userJoinedDate = moment(user.dateJoined); | ||||||||||||||||||
| const thresholdDate = moment(thresholdDateString); | ||||||||||||||||||
| const userJoinedDate = new Date(user.dateJoined); | ||||||||||||||||||
| // Reset time, so timezone will not flip the day | ||||||||||||||||||
| const thresholdDate = new Date(`${thresholdDateString}T00:00:00`); | ||||||||||||||||||
|
Comment on lines
+22
to
+23
|
||||||||||||||||||
| // Reset time, so timezone will not flip the day | |
| const thresholdDate = new Date(`${thresholdDateString}T00:00:00`); | |
| // Reset time, so timezone will not flip the day for date-only values. | |
| // If the env var already includes a time component (e.g. full ISO datetime), | |
| // parse it as-is to avoid creating an invalid date string. | |
| const thresholdDate = thresholdDateString.includes("T") | |
| ? new Date(thresholdDateString) | |
| : new Date(`${thresholdDateString}T00:00:00`); |
Uh oh!
There was an error while loading. Please reload this page.