-
-
- {mode !== "view" ? (
-
-
+
+
+
+
+
+
{visibleParticipants.length}
+ {canAddNewParticipant && mode !== "new" ? (
+
-
-
- {t("optionCount", { count: poll.options.length })}
+ >
+
+
+
+
+ ) : null}
- {isOverflowing || expanded ? (
-
-
-
-
-
-
-
-
-
-
-
-
-
- =
- scrollRef.current.scrollWidth,
- )}
- onClick={() => {
- goToNextPage();
- }}
- >
-
-
-
-
-
-
-
- {expanded ? (
-
-
- {
- collapse();
- }}
- />
-
-
-
-
-
- ) : (
-
-
- {
- expand();
- }}
- />
-
-
-
-
-
+
+
+ {poll.options[0]?.duration !== 0 && poll.timeZone ? (
+
+
+
+ ) : null}
+ {visibleParticipants.length > 0 || mode !== "view" ? (
+
+
0 ? "opacity-100" : "opacity-0",
)}
-
- ) : null}
-
-
- {poll.options[0]?.duration !== 0 && poll.timeZone ? (
-
-
-
- ) : null}
-
-
0 ? "opacity-100" : "opacity-0",
- )}
- />
-
-
-
-
-
-
- {mode === "new" ? (
- <>
-
-
- |
-
- >
- ) : null}
- {visibleParticipants.length > 0
- ? visibleParticipants.map((participant, i) => {
- return (
- {
- if (isEditing) {
- votingForm.setEditingParticipantId(
- participant.id,
- );
- }
- }}
- />
- );
- })
- : null}
-
-
-
-
- {mode !== "view" ? (
-
-
+ />
+
+
+
+
+
+
+
+ {mode === "new" ? (
+
+ ) : null}
+ {visibleParticipants.length > 0
+ ? visibleParticipants.map((participant, i) => {
+ return (
+ {
+ if (isEditing) {
+ votingForm.setEditingParticipantId(
+ participant.id,
+ );
+ }
+ }}
+ />
+ );
+ })
+ : null}
+
+
+
+
+ |
+ {poll.options.map((option) => {
+ return (
+
+
+
+
+ |
+ );
+ })}
+ |
+
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+ }}
+ defaults="Click Share to invite participants"
+ />
+
+
+ )}
+ {mode === "new" ? (
+
{
votingForm.cancel();
}}
>
- {t("cancel")}
+
- {mode === "new" ? (
-
- {t("continue")}
-
- ) : (
-
- {t("save")}
-
- )}
-
-
- ) : null}
+
+ }}
+ />
+
+
+
+
+
+ ) : null}
+
-
+
);
};
diff --git a/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx b/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx
index fbf5ebbd2..3178edcdd 100644
--- a/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx
+++ b/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx
@@ -1,26 +1,37 @@
import { cn } from "@rallly/ui";
+import { Button } from "@rallly/ui/button";
+import { Icon } from "@rallly/ui/icon";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipPortal,
+ TooltipTrigger,
+} from "@rallly/ui/tooltip";
+import { CheckIcon, UndoIcon } from "lucide-react";
import { useTranslation } from "next-i18next";
import * as React from "react";
import { Controller } from "react-hook-form";
import { useVotingForm } from "@/components/poll/voting-form";
+import { Trans } from "@/components/trans";
import { usePoll } from "../../poll-context";
import UserAvatar, { YouAvatar } from "../user-avatar";
-import { VoteSelector } from "../vote-selector";
+import { toggleVote, VoteSelector } from "../vote-selector";
export interface ParticipantRowFormProps {
name?: string;
className?: string;
isYou?: boolean;
+ isNew?: boolean;
onCancel?: () => void;
}
const ParticipantRowForm = ({
name,
+ isNew,
isYou,
className,
- onCancel,
}: ParticipantRowFormProps) => {
const { t } = useTranslation();
@@ -28,43 +39,106 @@ const ParticipantRowForm = ({
const form = useVotingForm();
React.useEffect(() => {
- window.addEventListener("keydown", (e) => {
+ function cancel(e: KeyboardEvent) {
if (e.key === "Escape") {
- onCancel?.();
+ form.cancel();
}
- });
- }, [onCancel]);
+ }
+ window.addEventListener("keydown", cancel);
+ return () => {
+ window.removeEventListener("keydown", cancel);
+ };
+ }, [form]);
return (
-
-
-
+
+
+
{name ? (
) : (
)}
+ {!isNew ? (
+
+
+
+ {
+ form.cancel();
+ }}
+ size="sm"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ) : null}
|
{optionIds.map((optionId, i) => {
return (
-
+ |
(
- {
- field.onChange({ optionId, type: vote });
+ {
+ field.onChange({
+ optionId,
+ type: toggleVote(field.value.type),
+ });
}}
- />
+ className="absolute inset-0 flex cursor-pointer items-center justify-center hover:bg-gray-100 active:bg-gray-200/50 active:ring-1 active:ring-inset active:ring-gray-200"
+ >
+ {
+ field.onChange({ optionId, type: vote });
+ }}
+ />
+
)}
/>
|
);
})}
+ |
);
};
diff --git a/apps/web/src/components/poll/desktop-poll/participant-row.tsx b/apps/web/src/components/poll/desktop-poll/participant-row.tsx
index cc30d7402..2db0d22b1 100644
--- a/apps/web/src/components/poll/desktop-poll/participant-row.tsx
+++ b/apps/web/src/components/poll/desktop-poll/participant-row.tsx
@@ -1,6 +1,7 @@
import { Participant, VoteType } from "@rallly/database";
+import { cn } from "@rallly/ui";
import { Button } from "@rallly/ui/button";
-import clsx from "clsx";
+import { Icon } from "@rallly/ui/icon";
import { MoreHorizontalIcon } from "lucide-react";
import * as React from "react";
@@ -33,35 +34,48 @@ export const ParticipantRowView: React.FunctionComponent<{
- |
{votes.map((vote, i) => {
return (
-
- |
);
};
@@ -105,7 +119,11 @@ const ParticipantRow: React.FunctionComponent = ({
align="start"
onEdit={() => onChangeEditMode?.(true)}
>
-
+
+
+
+
+
) : null
}
diff --git a/apps/web/src/components/poll/desktop-poll/poll-header.tsx b/apps/web/src/components/poll/desktop-poll/poll-header.tsx
index a5a9ba92f..613f35f78 100644
--- a/apps/web/src/components/poll/desktop-poll/poll-header.tsx
+++ b/apps/web/src/components/poll/desktop-poll/poll-header.tsx
@@ -1,26 +1,41 @@
import { cn } from "@rallly/ui";
-import clsx from "clsx";
+import { Icon } from "@rallly/ui/icon";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipPortal,
+ TooltipTrigger,
+} from "@rallly/ui/tooltip";
+import { ClockIcon } from "lucide-react";
import * as React from "react";
-import { DateIconInner } from "@/components/date-icon";
import { useOptions } from "@/components/poll-context";
-
-import { ConnectedScoreSummary } from "../score-summary";
+import { Trans } from "@/components/trans";
const TimeRange: React.FunctionComponent<{
start: string;
end: string;
+ duration: string;
className?: string;
-}> = ({ start, end, className }) => {
+}> = ({ start, end, duration, className }) => {
return (
-
- {start}
- {end}
+
+
+ {start}
+
+
+
+ {start} - {end}
+
+
+
+
+
+ {duration}
+
+
+
+
);
};
@@ -36,33 +51,16 @@ const TimelineRow = ({
className="sticky left-0 z-30 bg-white pl-4 pr-4"
>
{children}
- |
+ |
|
);
};
const monthRowHeight = 48;
-const dayRowHeight = 64;
+const dayRowHeight = 60;
const scoreRowTop = monthRowHeight + dayRowHeight;
-const Trail = ({ end }: { end?: boolean }) => {
- return end ? (
-
- ) : (
-
- );
-};
-
const PollHeader: React.FunctionComponent = () => {
const { options } = useOptions();
return (
@@ -71,26 +69,25 @@ const PollHeader: React.FunctionComponent = () => {
{options.map((option, i) => {
const firstOfMonth =
i === 0 || options[i - 1]?.month !== option.month;
- const lastOfMonth = options[i + 1]?.month !== option.month;
return (
-
- {firstOfMonth ? null : }
+
- {option.month}
+ {option.month}
+ {option.year}
|
@@ -103,31 +100,35 @@ const PollHeader: React.FunctionComponent = () => {
i === 0 ||
options[i - 1]?.day !== option.day ||
options[i - 1]?.month !== option.month;
+
const lastOfDay =
- options[i + 1]?.day !== option.day ||
- options[i + 1]?.month !== option.month;
+ i === options.length - 1 || options[i + 1]?.day !== option.day;
return (
- {firstOfDay ? null : }
-
+ {firstOfDay ? (
+
+
+ {option.dow}
+
+ {option.day}
+
+ ) : null}
|
);
})}
@@ -138,13 +139,20 @@ const PollHeader: React.FunctionComponent = () => {
- {option.type === "timeSlot" ? (
-
- ) : null}
-
-
+
+ {option.type === "timeSlot" ? (
+
+ ) : (
+
+
+
+ )}
|
);
diff --git a/apps/web/src/components/poll/guest-alert.tsx b/apps/web/src/components/poll/guest-alert.tsx
new file mode 100644
index 000000000..e69de29bb
diff --git a/apps/web/src/components/poll/language-selector.tsx b/apps/web/src/components/poll/language-selector.tsx
index 21bdee660..508e46f1d 100644
--- a/apps/web/src/components/poll/language-selector.tsx
+++ b/apps/web/src/components/poll/language-selector.tsx
@@ -1,4 +1,5 @@
import languages from "@rallly/languages";
+import { Button } from "@rallly/ui/button";
import {
Select,
SelectContent,
@@ -14,8 +15,10 @@ export const LanguageSelect: React.FunctionComponent<{
}> = ({ className, value, onChange }) => {
return (