sendou.ink/app/features/plus-suggestions/routes/plus.suggestions.comment.$tier.$userId.tsx
Kalle 9312fad90f
Tournament organization page (#1811)
* Initial

* Calendar initial

* Extract EventCalendar

* Events list initial

* Winners

* SQL fixes

* List events by series

* Leaderboards

* Series leaderboard

* Own entry peek

* Edit page skeleton

* RHF initial test

* RHF stuff

* Form etc. progress

* Fix tournament series description

* Fix tabs layout

* Fix socials insert

* Check for not removing admin

* Adding series

* TODOs

* Allow updating org with no series

* FormFieldset

* Allow series without events

* TextAreaFormfield accepting array syntax

* Input form array field

* ToggleFormField

* SelectFormField

* UserSearchFormField

* Fetch badgeOptions

* Badge editing

* Progress

* Use native preventScrollReset

* Rename func

* Fix sticky scroll

* Fix translation

* i18n errors

* handle,meta in edit

* Add ref to user search

* TODOs

* Done
2024-07-25 23:06:29 +03:00

127 lines
3.6 KiB
TypeScript

import type { ActionFunction } from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { Form, useMatches, useParams } from "@remix-run/react";
import { z } from "zod";
import { Button, LinkButton } from "~/components/Button";
import { Dialog } from "~/components/Dialog";
import { Redirect } from "~/components/Redirect";
import { PLUS_TIERS, PlUS_SUGGESTION_COMMENT_MAX_LENGTH } from "~/constants";
import { useUser } from "~/features/auth/core/user";
import { requireUser } from "~/features/auth/core/user.server";
import * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server";
import {
nextNonCompletedVoting,
rangeToMonthYear,
} from "~/features/plus-voting/core";
import {
canAddCommentToSuggestionBE,
canAddCommentToSuggestionFE,
} from "~/permissions";
import { atOrError } from "~/utils/arrays";
import { parseRequestPayload, validate } from "~/utils/remix";
import { plusSuggestionPage } from "~/utils/urls";
import { actualNumber, trimmedString } from "~/utils/zod";
import type { PlusSuggestionsLoaderData } from "./plus.suggestions";
import { CommentTextarea } from "./plus.suggestions.new";
const commentActionSchema = z.object({
comment: z.preprocess(
trimmedString,
z.string().min(1).max(PlUS_SUGGESTION_COMMENT_MAX_LENGTH),
),
tier: z.preprocess(
actualNumber,
z
.number()
.min(Math.min(...PLUS_TIERS))
.max(Math.max(...PLUS_TIERS)),
),
suggestedId: z.preprocess(actualNumber, z.number()),
});
export const action: ActionFunction = async ({ request }) => {
const data = await parseRequestPayload({
request,
schema: commentActionSchema,
});
const user = await requireUser(request);
const votingMonthYear = rangeToMonthYear(nextNonCompletedVoting(new Date()));
const suggestions =
await PlusSuggestionRepository.findAllByMonth(votingMonthYear);
validate(suggestions);
validate(
canAddCommentToSuggestionBE({
suggestions,
user,
suggested: { id: data.suggestedId },
targetPlusTier: data.tier,
}),
);
await PlusSuggestionRepository.create({
authorId: user.id,
suggestedId: data.suggestedId,
text: data.comment,
tier: data.tier,
...votingMonthYear,
});
throw redirect(plusSuggestionPage(data.tier));
};
export default function PlusCommentModalPage() {
const user = useUser();
const matches = useMatches();
const params = useParams();
const data = atOrError(matches, -2).data as PlusSuggestionsLoaderData;
const targetUserId = Number(params.userId);
const tierSuggestedTo = String(params.tier);
const userBeingCommented = data.suggestions.find(
(suggestion) =>
suggestion.tier === Number(tierSuggestedTo) &&
suggestion.suggested.id === targetUserId,
);
if (
!data.suggestions ||
!userBeingCommented ||
!canAddCommentToSuggestionFE({
user,
suggestions: data.suggestions,
suggested: { id: targetUserId },
targetPlusTier: Number(tierSuggestedTo),
})
) {
return <Redirect to={plusSuggestionPage()} />;
}
return (
<Dialog isOpen>
<Form method="post" className="stack md">
<input type="hidden" name="tier" value={tierSuggestedTo} />
<input type="hidden" name="suggestedId" value={targetUserId} />
<h2 className="plus__modal-title">
{userBeingCommented.suggested.username}&apos;s +{tierSuggestedTo}{" "}
suggestion
</h2>
<CommentTextarea maxLength={PlUS_SUGGESTION_COMMENT_MAX_LENGTH} />
<div className="plus__modal-buttons">
<Button type="submit">Submit</Button>
<LinkButton
to={plusSuggestionPage()}
variant="minimal-destructive"
size="tiny"
>
Cancel
</LinkButton>
</div>
</Form>
</Dialog>
);
}