mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-02 02:31:53 +02:00
Add locale support (#228)
This commit is contained in:
parent
800af20132
commit
416a17c5b7
47 changed files with 967 additions and 467 deletions
|
@ -1,12 +1,14 @@
|
|||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { Trans, useTranslation } from "next-i18next";
|
||||
import * as React from "react";
|
||||
import { useMeasure } from "react-use";
|
||||
import smoothscroll from "smoothscroll-polyfill";
|
||||
|
||||
import ArrowLeft from "@/components/icons/arrow-left.svg";
|
||||
import ArrowRight from "@/components/icons/arrow-right.svg";
|
||||
import Check from "@/components/icons/check.svg";
|
||||
import Plus from "@/components/icons/plus-sm.svg";
|
||||
|
||||
import { Button } from "../button";
|
||||
import ArrowLeft from "../icons/arrow-left.svg";
|
||||
import ArrowRight from "../icons/arrow-right.svg";
|
||||
import { useParticipants } from "../participants-provider";
|
||||
import { usePoll } from "../poll-context";
|
||||
import TimeZonePicker from "../time-zone-picker";
|
||||
|
@ -14,11 +16,10 @@ import ParticipantRow from "./desktop-poll/participant-row";
|
|||
import ParticipantRowForm from "./desktop-poll/participant-row-form";
|
||||
import { PollContext } from "./desktop-poll/poll-context";
|
||||
import PollHeader from "./desktop-poll/poll-header";
|
||||
import { useAddParticipantMutation } from "./mutations";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
smoothscroll.polyfill();
|
||||
}
|
||||
import {
|
||||
useAddParticipantMutation,
|
||||
useUpdateParticipantMutation,
|
||||
} from "./mutations";
|
||||
|
||||
const MotionButton = motion(Button);
|
||||
|
||||
|
@ -27,7 +28,8 @@ const minSidebarWidth = 200;
|
|||
const Poll: React.VoidFunctionComponent = () => {
|
||||
const { t } = useTranslation("app");
|
||||
|
||||
const { poll, options, targetTimeZone, setTargetTimeZone } = usePoll();
|
||||
const { poll, options, targetTimeZone, setTargetTimeZone, userAlreadyVoted } =
|
||||
usePoll();
|
||||
|
||||
const { participants } = useParticipants();
|
||||
|
||||
|
@ -35,7 +37,7 @@ const Poll: React.VoidFunctionComponent = () => {
|
|||
const [editingParticipantId, setEditingParticipantId] =
|
||||
React.useState<string | null>(null);
|
||||
|
||||
const actionColumnWidth = 140;
|
||||
const actionColumnWidth = 100;
|
||||
const columnWidth = Math.min(
|
||||
130,
|
||||
Math.max(
|
||||
|
@ -65,7 +67,8 @@ const Poll: React.VoidFunctionComponent = () => {
|
|||
const maxScrollPosition =
|
||||
columnWidth * options.length - columnWidth * numberOfVisibleColumns;
|
||||
|
||||
const shouldShowNewParticipantForm = !poll.closed;
|
||||
const [shouldShowNewParticipantForm, setShouldShowNewParticipantForm] =
|
||||
React.useState(!poll.closed && !userAlreadyVoted);
|
||||
|
||||
const pollWidth =
|
||||
sidebarWidth + options.length * columnWidth + actionColumnWidth;
|
||||
|
@ -87,6 +90,8 @@ const Poll: React.VoidFunctionComponent = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const updateParticipant = useUpdateParticipantMutation();
|
||||
|
||||
const participantListContainerRef = React.useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<PollContext.Provider
|
||||
|
@ -192,28 +197,93 @@ const Poll: React.VoidFunctionComponent = () => {
|
|||
isEditing ? participant.id : null,
|
||||
);
|
||||
}}
|
||||
onSubmit={async ({ name, votes }) => {
|
||||
await updateParticipant.mutateAsync({
|
||||
participantId: participant.id,
|
||||
pollId: poll.id,
|
||||
votes,
|
||||
name,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
{shouldShowNewParticipantForm ? (
|
||||
{shouldShowNewParticipantForm &&
|
||||
!poll.closed &&
|
||||
!editingParticipantId ? (
|
||||
<ParticipantRowForm
|
||||
className="border-t bg-gray-50"
|
||||
className="shrink-0 border-t bg-gray-50"
|
||||
onSubmit={async ({ name, votes }) => {
|
||||
const participant = await addParticipant.mutateAsync({
|
||||
await addParticipant.mutateAsync({
|
||||
name,
|
||||
votes,
|
||||
pollId: poll.id,
|
||||
});
|
||||
setTimeout(() => {
|
||||
participantListContainerRef.current
|
||||
?.querySelector(`[data-participantid=${participant.id}]`)
|
||||
?.scrollIntoView();
|
||||
}, 100);
|
||||
setShouldShowNewParticipantForm(false);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{!poll.closed ? (
|
||||
<div className="flex h-14 shrink-0 items-center border-t bg-gray-50 px-3">
|
||||
{shouldShowNewParticipantForm || editingParticipantId ? (
|
||||
<div className="flex items-center space-x-3">
|
||||
<Button
|
||||
key="submit"
|
||||
form="participant-row-form"
|
||||
htmlType="submit"
|
||||
type="primary"
|
||||
icon={<Check />}
|
||||
loading={
|
||||
addParticipant.isLoading || updateParticipant.isLoading
|
||||
}
|
||||
>
|
||||
{t("save")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (editingParticipantId) {
|
||||
setEditingParticipantId(null);
|
||||
} else {
|
||||
setShouldShowNewParticipantForm(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<div className="text-sm">
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="saveInstruction"
|
||||
values={{
|
||||
save: t("save"),
|
||||
}}
|
||||
components={{ b: <strong /> }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex w-full items-center space-x-3">
|
||||
<Button
|
||||
key="add-participant"
|
||||
onClick={() => {
|
||||
setShouldShowNewParticipantForm(true);
|
||||
}}
|
||||
icon={<Plus />}
|
||||
>
|
||||
{t("addParticipant")}
|
||||
</Button>
|
||||
{userAlreadyVoted ? (
|
||||
<div className="flex items-center text-sm text-gray-400">
|
||||
<Check className="mr-1 h-5" />
|
||||
<div>{t("alreadyVoted")}</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</PollContext.Provider>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue