Repository navigation
Conversation
|
Adds polls to the editor and preview 😁 |
|
Don't have time to review yet but would it be possible for you to split polls into a separate PR since they require extra work? |
shayypy
left a comment
There was a problem hiding this comment.
For some reason my git client is checking out 84 when I try to check out 86, so I can't actually make any changes myself right now, but these are the things I noticed while looking this over on GH
| <span className="truncate"> | ||
| {`Answer ${index + 1}`} | ||
| {previewText ? ` - ${previewText}` : ""} | ||
| </span> |
| <p className="truncate"> | ||
| Poll | ||
| {previewText ? ` - ${previewText}` : ""} | ||
| </p> |
There was a problem hiding this comment.
Should also be localized, see comment on answer component
| <div className="space-y-2"> | ||
| {disabled && ( | ||
| <InfoBox severity="blue" icon="Info"> | ||
| Polls cannot be edited for existing messages. |
There was a problem hiding this comment.
| Polls cannot be edited for existing messages. | |
| {t("pollsImmutable")} |
Add to i18n
| {disabled && ( | ||
| <InfoBox severity="blue" icon="Info"> | ||
| Polls cannot be edited for existing messages. | ||
| </InfoBox> | ||
| )} |
There was a problem hiding this comment.
| {disabled && ( | |
| <InfoBox severity="blue" icon="Info"> | |
| Polls cannot be edited for existing messages. | |
| </InfoBox> | |
| )} | |
| {disabled ? ( | |
| <InfoBox severity="blue" icon="Info"> | |
| Polls cannot be edited for existing messages. | |
| </InfoBox> | |
| ) : null} |
I prefer to use a ternary operator these days but it's not a huge deal since disabled is a bool
| const answers = [...poll.answers]; | ||
| answers.splice(index, 1, updatedAnswer); | ||
| updatePoll({ ...poll, answers }); |
There was a problem hiding this comment.
Not sure if the double spread is necessary. You aren't duplicating poll (otherwise you'd use structuredClone) so I think just the one spread in updatePoll would be fine, splicing the original array to update the answer, unless I do something else in another example. Ditto for the other callbacks here of course
| return ( | ||
| <img | ||
| src={cdn.emoji(emoji.id, emoji.animated ? "gif" : "webp")} | ||
| className="h-[22px] w-[22px] shrink-0 object-contain" |
There was a problem hiding this comment.
| className="h-[22px] w-[22px] shrink-0 object-contain" | |
| className="size-[22px] shrink-0 object-contain" |
| return ( | ||
| <Twemoji | ||
| emoji={emoji.name} | ||
| className="h-[22px] w-[22px] shrink-0 align-middle" |
There was a problem hiding this comment.
| className="h-[22px] w-[22px] shrink-0 align-middle" | |
| className="size-[22px] shrink-0 align-middle" |
| {poll.question.text} | ||
| </h4> | ||
| <div className="mt-1 text-muted dark:text-muted-dark text-[14px]"> | ||
| Select one answer |
There was a problem hiding this comment.
| Select one answer | |
| {t("selectOneAnswer")} |
| poll: NonNullable<QueryData["messages"][number]["data"]["poll"]>; | ||
| }> = ({ poll }) => { |
There was a problem hiding this comment.
| poll: NonNullable<QueryData["messages"][number]["data"]["poll"]>; | |
| }> = ({ poll }) => { | |
| t: TFunction; | |
| poll: NonNullable<QueryData["messages"][number]["data"]["poll"]>; | |
| }> = ({ t, poll }) => { |
It would probably be fine to call useTranslation in this component but I think I usually simply pass it to preview components like this
| <div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer"> | ||
| 0 votes | ||
| </div> | ||
| <div className="before:mx-2 before:text-[20px] before:leading-none before:content-['\2219'] text-muted dark:text-muted-dark" /> | ||
| <div className="text-muted dark:text-muted-dark"> | ||
| {poll.duration ?? 24}h left | ||
| </div> | ||
| </div> | ||
| <div className="flex items-center gap-4"> | ||
| <div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer text-[14px]"> | ||
| Show results | ||
| </div> | ||
| <Button disabled>Vote</Button> |
There was a problem hiding this comment.
| <div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer"> | |
| 0 votes | |
| </div> | |
| <div className="before:mx-2 before:text-[20px] before:leading-none before:content-['\2219'] text-muted dark:text-muted-dark" /> | |
| <div className="text-muted dark:text-muted-dark"> | |
| {poll.duration ?? 24}h left | |
| </div> | |
| </div> | |
| <div className="flex items-center gap-4"> | |
| <div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer text-[14px]"> | |
| Show results | |
| </div> | |
| <Button disabled>Vote</Button> | |
| <div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer"> | |
| {t("nVotes", { count: 0 })} | |
| </div> | |
| <div className="before:mx-2 before:text-[20px] before:leading-none before:content-['\2219'] text-muted dark:text-muted-dark" /> | |
| <div className="text-muted dark:text-muted-dark"> | |
| {t("pollDurationLeft", { values: { hours: poll.duration ?? 24 } })} | |
| </div> | |
| </div> | |
| <div className="flex items-center gap-4"> | |
| <div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer text-[14px]"> | |
| {t("showResults")} | |
| </div> | |
| <Button disabled>{t("vote")}</Button> |
Polls in Discord actually change the unit based on the amount of time remaining and do not only show hours. I'd like to do that here as well, a la timestamp.relative.*
The localization w/ count for a constant 0 votes might seem weird but I'd rather it be more "realistic" so to speak. Also, I may implement a feature to fetch vote data for the preview, so we want a real localized count there.
|
Another thing, don't bother with splitting polls into a new PR, I'll just merge this and then mark it as an experiment so I can keep working on it. |

Before:

After:
