Skip to content

Commit

Permalink
Remove moment.js from frontend (fix #91)
Browse files Browse the repository at this point in the history
  • Loading branch information
PurkkaKoodari committed Aug 5, 2024
1 parent 443c6c8 commit 271b41c
Show file tree
Hide file tree
Showing 25 changed files with 239 additions and 186 deletions.
3 changes: 1 addition & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ module.exports = {
"**/test/**",
"**/vite.config.ts",
"**/vitest.config.ts",
"**/.eslintrc.js",
"**/rollupMomentPlugin.ts"
"**/.eslintrc.js"
],
}],
// Sort imports: React first, then npm packages, then local files, then CSS.
Expand Down
1 change: 0 additions & 1 deletion docs/project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ Libraries:
- [React Router](https://reactrouter.com/)
- [i18next](https://www.i18next.com/) for internationalization
- [Formik](https://formik.org/)
- [MomentJS](https://momentjs.com/) - will transition to something else in the future

## Frontend serving

Expand Down
2 changes: 0 additions & 2 deletions packages/ilmomasiina-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
"final-form": "^4.20.10",
"i18next": "^23.10.0",
"lodash-es": "^4.17.21",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
"react": "^17 || ^18.2.0",
"react-bootstrap": "^1.6.8",
"react-countdown": "^2.3.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/ilmomasiina-components/src/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"components": {
"dateFormat.dateTimeSep": "at",
"dateFormat.locale": "en-FI",
"editSignup.backToEvent": "Back to event page",
"editSignup.action.cancel": "Cancel",
"editSignup.action.edit": "Update",
Expand Down
2 changes: 1 addition & 1 deletion packages/ilmomasiina-components/src/locales/fi.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"components": {
"dateFormat.dateTimeSep": "klo",
"dateFormat.locale": "fi-FI",
"editSignup.backToEvent": "Takaisin tapahtumasivulle",
"editSignup.action.cancel": "Peruuta",
"editSignup.action.edit": "Päivitä",
Expand Down
22 changes: 17 additions & 5 deletions packages/ilmomasiina-components/src/routes/Events/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,30 @@ import { Spinner, Table } from "react-bootstrap";
import { useTranslation } from "react-i18next";

import { ErrorCode } from "@tietokilta/ilmomasiina-models";
import { timezone } from "../../config";
import { linkComponent, Navigate } from "../../config/router";
import { usePaths } from "../../contexts/paths";
import { I18nProvider } from "../../i18n";
import { EventListProps, EventListProvider, useEventListContext } from "../../modules/events";
import { useEventDateFormatter } from "../../utils/dateFormat";
import { errorDesc, errorTitle } from "../../utils/errorMessage";
import { EventRow, eventsToRows, QuotaRow } from "../../utils/eventListUtils";
import { useSignupStateText } from "../../utils/signupStateText";
import TableRow from "./components/TableRow";

const ListEventRow = ({ row: { slug, title, date, signupState, signupCount, quotaSize } }: { row: EventRow }) => {
const ListEventRow = ({
row: { slug, title, date, signupState, signupCount, quotaSize },
}: {
row: EventRow;
}) => {
const Link = linkComponent();
const paths = usePaths();
const stateText = useSignupStateText(signupState);
const eventDateFormat = useEventDateFormatter();
return (
<TableRow
className={stateText.class}
title={<Link to={paths.eventDetails(slug)}>{title}</Link>}
date={date ? date.tz(timezone()).format("DD.MM.YYYY") : ""}
date={date ? eventDateFormat.format(date) : ""}
signupStatus={stateText}
signupCount={signupCount}
quotaSize={quotaSize}
Expand All @@ -47,7 +52,10 @@ const EventListView = () => {
const { t } = useTranslation();
const paths = usePaths();

const tableRows = useMemo(() => eventsToRows(events ?? []).filter((row) => row.type !== "waitlist"), [events]);
const tableRows = useMemo(
() => eventsToRows(events ?? []).filter((row) => row.type !== "waitlist"),
[events],
);

// If initial setup is needed and is possible on this frontend, redirect to that page.
if (error && error.code === ErrorCode.INITIAL_SETUP_NEEDED && paths.hasAdmin) {
Expand Down Expand Up @@ -86,7 +94,11 @@ const EventListView = () => {
</thead>
<tbody>
{tableRows.map((row) =>
row.type === "event" ? <ListEventRow key={row.id} row={row} /> : <ListQuotaRow key={row.id} row={row} />,
row.type === "event" ? (
<ListEventRow key={row.id} row={row} />
) : (
<ListQuotaRow key={row.id} row={row} />
),
)}
</tbody>
</Table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React, { useContext } from "react";

import moment from "moment-timezone";
import { Button } from "react-bootstrap";
import { useTranslation } from "react-i18next";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

import { timezone } from "../../../config";
import { linkComponent } from "../../../config/router";
import AuthContext from "../../../contexts/auth";
import { usePaths } from "../../../contexts/paths";
import { useSingleEventContext } from "../../../modules/singleEvent";
import { useEventDateTimeFormatter } from "../../../utils/dateFormat";

const EventDescription = () => {
const event = useSingleEventContext().event!;
const { loggedIn } = useContext(AuthContext);
const Link = linkComponent();
const paths = usePaths();
const { t } = useTranslation();
const eventDateFormat = useEventDateTimeFormatter();
return (
<>
<nav className="ilmo--title-nav">
Expand All @@ -36,18 +36,16 @@ const EventDescription = () => {
)}
{event.date && (
<p>
<strong>{event.endDate ? t("singleEvent.info.startDate") : t("singleEvent.info.date")}</strong>{" "}
{moment(event.date)
.tz(timezone())
.format(`D.M.Y [${t("dateFormat.dateTimeSep")}] HH:mm`)}
<strong>
{event.endDate ? t("singleEvent.info.startDate") : t("singleEvent.info.date")}
</strong>{" "}
{eventDateFormat.format(new Date(event.date))}
</p>
)}
{event.endDate && (
<p>
<strong>{t("singleEvent.info.endDate")}</strong>{" "}
{moment(event.endDate)
.tz(timezone())
.format(`D.M.Y [${t("dateFormat.dateTimeSep")}] HH:mm`)}
{eventDateFormat.format(new Date(event.endDate))}
</p>
)}
{event.location && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React from "react";

import moment from "moment";
import Countdown from "react-countdown";

import { useSingleEventContext } from "../../../modules/singleEvent";
import SignupButton from "./SignupButton";

const SignupCountdown = () => {
const event = useSingleEventContext().event!;
const openingTime = moment()
.add(event.millisTillOpening || 0, "ms")
.toDate();
const openingTime = new Date(Date.now() + (event.millisTillOpening || 0));

return (
<Countdown
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import React from "react";

import filter from "lodash-es/filter";
import find from "lodash-es/find";
import moment from "moment-timezone";
import { useTranslation } from "react-i18next";

import { timezone } from "../../../config";
import { useSingleEventContext } from "../../../modules/singleEvent";
import {
useActionDateTimeFormatter,
useMillisecondsDateTimeFormatter,
} from "../../../utils/dateFormat";
import { SignupWithQuota, stringifyAnswer } from "../../../utils/signupUtils";

type Props = {
Expand All @@ -20,6 +22,8 @@ const SignupListRow = ({ showQuota, signup, index }: Props) => {

const { questions, nameQuestion } = useSingleEventContext().event!;
const { t } = useTranslation();
const actionDateFormat = useActionDateTimeFormatter();
const msDateFormat = useMillisecondsDateTimeFormatter();

let fullName;
if (!confirmed) {
Expand All @@ -33,14 +37,18 @@ const SignupListRow = ({ showQuota, signup, index }: Props) => {
return (
<tr className={!confirmed ? "ilmo--unconfirmed" : ""}>
<td>{`${index}.`}</td>
{nameQuestion && <td className={!confirmed || !namePublic ? "ilmo--hidden-name" : ""}>{fullName}</td>}
{nameQuestion && (
<td className={!confirmed || !namePublic ? "ilmo--hidden-name" : ""}>{fullName}</td>
)}
{filter(questions, "public").map((question) => (
<td key={question.id}>{stringifyAnswer(find(answers, { questionId: question.id })?.answer || "")}</td>
<td key={question.id}>
{stringifyAnswer(find(answers, { questionId: question.id })?.answer || "")}
</td>
))}
{showQuota && <td>{quotaName || ""}</td>}
<td>
{moment(createdAt).tz(timezone()).format("DD.MM.YYYY HH:mm:ss")}
<span className="ilmo--hover-only">{moment(createdAt).tz(timezone()).format(".SSS")}</span>
{actionDateFormat.format(new Date(createdAt))}
<span className="ilmo--hover-only">{msDateFormat.format(new Date(createdAt))}</span>
</td>
</tr>
);
Expand Down
71 changes: 71 additions & 0 deletions packages/ilmomasiina-components/src/utils/dateFormat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useTranslation } from "react-i18next";

import { timezone } from "../config";

/** Returns a formatter for event dates like "31.12.2024". */
export function useEventDateFormatter() {
const { t } = useTranslation();
const locale = t("dateFormat.locale");
return new Intl.DateTimeFormat(locale, {
day: "numeric",
month: "numeric",
year: "numeric",
hour12: false,
timeZone: timezone(),
});
}

/** Returns a formatter for event datetimes like "su 31.12.2024 23:59". */
export function useEventDateTimeFormatter() {
const { t } = useTranslation();
const locale = t("dateFormat.locale");
return new Intl.DateTimeFormat(locale, {
weekday: "short",
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
hour12: false,
timeZone: timezone(),
});
}

/** Returns a formatter for seconds-accurate datetimes like "31.12.2024 23:59:59". */
export function useActionDateTimeFormatter() {
const { t } = useTranslation();
const locale = t("dateFormat.locale");
return new Intl.DateTimeFormat(locale, {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: false,
timeZone: timezone(),
});
}

/** Returns a formatter for the milliseconds of a time. */
export function useMillisecondsDateTimeFormatter() {
const { t } = useTranslation();
const locale = t("dateFormat.locale");
return new Intl.DateTimeFormat(locale, {
fractionalSecondDigits: 3,
});
}

/** Returns a formatter for seconds-accurate datetimes like "31.12.2024 23:59:59". */
export function getCsvDateTimeFormatter() {
return new Intl.DateTimeFormat("fi-FI", {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: false,
timeZone: timezone(),
});
}
20 changes: 15 additions & 5 deletions packages/ilmomasiina-components/src/utils/eventListUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import every from "lodash-es/every";
import sumBy from "lodash-es/sumBy";
import moment, { Moment } from "moment-timezone";

import type {
EventID,
Expand All @@ -21,7 +20,7 @@ export type EventRow = {
type: "event";
slug: EventSlug;
title: string;
date: Moment | null;
date: Date | null;
signupState: SignupStateInfo;
signupCount?: number;
quotaSize?: number | null;
Expand All @@ -39,7 +38,16 @@ export type TableRow = EventRow | QuotaRow;

/** Converts an event to rows to be shown in the event list. */
export function eventToRows(event: UserEventListItem, { compact }: EventTableOptions = {}) {
const { id, slug, title, date, registrationStartDate, registrationEndDate, quotas, openQuotaSize } = event;
const {
id,
slug,
title,
date,
registrationStartDate,
registrationEndDate,
quotas,
openQuotaSize,
} = event;
const state = signupState(registrationStartDate, registrationEndDate);

// Event row
Expand All @@ -50,7 +58,7 @@ export function eventToRows(event: UserEventListItem, { compact }: EventTableOpt
signupState: state,
slug,
title,
date: date ? moment(date) : null,
date: date ? new Date(date) : null,
signupCount: quotas.length < 2 ? sumBy(quotas, "signupCount") : undefined,
quotaSize: quotas.length === 1 ? quotas[0].size : undefined,
totalSignupCount: sumBy(quotas, "signupCount") ?? 0,
Expand All @@ -74,7 +82,9 @@ export function eventToRows(event: UserEventListItem, { compact }: EventTableOpt
);
}

const overflow = sumBy(quotas, (quota) => (quota.size ? Math.max(0, quota.signupCount - quota.size) : 0));
const overflow = sumBy(quotas, (quota) =>
quota.size ? Math.max(0, quota.signupCount - quota.size) : 0,
);

// Open quota
if (openQuotaSize > 0) {
Expand Down
Loading

0 comments on commit 271b41c

Please sign in to comment.