mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-24 06:58:10 -05:00
suggestion frontend
This commit is contained in:
parent
ec77a7c1b6
commit
94bda2e1b0
|
|
@ -71,6 +71,7 @@ const UserSelector: React.FC<SingleSelectorProps | MultiSelectorProps> = ({
|
|||
),
|
||||
}}
|
||||
hideMenuBeforeTyping
|
||||
isClearable={!isMulti}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
|||
21
components/plus/PlusHomePage.tsx
Normal file
21
components/plus/PlusHomePage.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Button } from "@chakra-ui/button";
|
||||
import { Box } from "@chakra-ui/layout";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import SuggestionVouchModal from "./SuggestionVouchModal";
|
||||
|
||||
export interface PlusHomePageProps {}
|
||||
|
||||
const PlusHomePage: React.FC<PlusHomePageProps> = () => {
|
||||
return (
|
||||
<>
|
||||
<SuggestionVouchModal
|
||||
canSuggest={true}
|
||||
canVouch={false}
|
||||
userPlusTier={1}
|
||||
/>
|
||||
<Box>No suggestions yet for this month</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlusHomePage;
|
||||
142
components/plus/SuggestionVouchModal.tsx
Normal file
142
components/plus/SuggestionVouchModal.tsx
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalCloseButton,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
ModalContent,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Textarea,
|
||||
FormHelperText,
|
||||
FormErrorMessage,
|
||||
Select,
|
||||
} from "@chakra-ui/react";
|
||||
import { Trans, t } from "@lingui/macro";
|
||||
import { useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import {
|
||||
suggestionSchema,
|
||||
SUGGESTION_DESCRIPTION_LIMIT,
|
||||
} from "lib/validators/suggestion";
|
||||
import * as z from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import UserSelector from "components/common/UserSelector";
|
||||
|
||||
interface Props {
|
||||
canVouch: boolean;
|
||||
canSuggest: boolean;
|
||||
userPlusTier: number;
|
||||
}
|
||||
|
||||
type FormData = z.infer<typeof suggestionSchema>;
|
||||
|
||||
const SuggestionVouchModal: React.FC<Props> = ({
|
||||
canVouch,
|
||||
canSuggest,
|
||||
userPlusTier,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const sending = false; //usemutation hook
|
||||
const { handleSubmit, errors, register, watch, control } = useForm<FormData>({
|
||||
resolver: zodResolver(suggestionSchema),
|
||||
});
|
||||
|
||||
const watchDescription = watch("description", "");
|
||||
|
||||
if (!canVouch && !canSuggest) return null;
|
||||
|
||||
const getButtonText = () => {
|
||||
if (canSuggest && canVouch) return t`Add new suggestion or vouch`;
|
||||
if (canVouch) return t`Vouch`;
|
||||
|
||||
return t`Add new suggestion`;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button size="sm" mb={4} onClick={() => setIsOpen(true)}>
|
||||
{getButtonText()}
|
||||
</Button>
|
||||
{isOpen && (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={() => setIsOpen(false)}
|
||||
size="xl"
|
||||
closeOnOverlayClick={false}
|
||||
>
|
||||
<ModalOverlay>
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
<Trans>Adding a new suggestion or vouch</Trans>
|
||||
</ModalHeader>
|
||||
<ModalCloseButton borderRadius="50%" />
|
||||
<form>
|
||||
<ModalBody pb={2}>
|
||||
<FormLabel>
|
||||
<Trans>Tier</Trans>
|
||||
</FormLabel>
|
||||
<Controller
|
||||
name="tier"
|
||||
control={control}
|
||||
defaultValue={1}
|
||||
render={({ value, onChange }) => (
|
||||
<Select
|
||||
value={value}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
>
|
||||
{userPlusTier === 1 && <option value="1">+1</option>}
|
||||
{userPlusTier <= 2 && <option value="2">+2</option>}
|
||||
{false && <option value="3">+3</option>}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
<FormLabel mt={4}>
|
||||
<Trans>User</Trans>
|
||||
</FormLabel>
|
||||
<Controller
|
||||
name="suggestedUserId"
|
||||
control={control}
|
||||
render={({ value, onChange }) => (
|
||||
<UserSelector
|
||||
value={value}
|
||||
setValue={onChange}
|
||||
isMulti={false}
|
||||
maxMultiCount={undefined}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<FormControl isInvalid={!!errors.description}>
|
||||
<FormLabel htmlFor="description" mt={4}>
|
||||
<Trans>Description</Trans>
|
||||
</FormLabel>
|
||||
<Textarea name="description" ref={register} />
|
||||
<FormHelperText>
|
||||
{(watchDescription ?? "").length}/
|
||||
{SUGGESTION_DESCRIPTION_LIMIT}
|
||||
</FormHelperText>
|
||||
<FormErrorMessage>
|
||||
{errors.description?.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button mr={3} type="submit" isLoading={sending}>
|
||||
<Trans>Save</Trans>
|
||||
</Button>
|
||||
<Button onClick={() => setIsOpen(false)} variant="outline">
|
||||
<Trans>Cancel</Trans>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</ModalOverlay>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SuggestionVouchModal;
|
||||
9
lib/validators/suggestion.ts
Normal file
9
lib/validators/suggestion.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import * as z from "zod";
|
||||
|
||||
export const SUGGESTION_DESCRIPTION_LIMIT = 500;
|
||||
|
||||
export const suggestionSchema = z.object({
|
||||
description: z.string().max(SUGGESTION_DESCRIPTION_LIMIT),
|
||||
suggestedUserId: z.number().int(),
|
||||
tier: z.number().int().min(1).max(3),
|
||||
});
|
||||
40
pages/plus/index.tsx
Normal file
40
pages/plus/index.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import PlusHomePage from "components/plus/PlusHomePage";
|
||||
|
||||
// export const getStaticProps: GetStaticProps<PlusVotingHistoryPageProps> = async ({
|
||||
// params,
|
||||
// }) => {
|
||||
// const getSlug = async () => {
|
||||
// const slug = Array.isArray(params!.slug) ? params!.slug : [];
|
||||
// if (slug.length === 3) {
|
||||
// return slug;
|
||||
// }
|
||||
|
||||
// if (slug.length > 0) {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
// const mostRecent = await plusService.getMostRecentVotingWithResultsMonth();
|
||||
|
||||
// return ["1", mostRecent.year, mostRecent.month];
|
||||
// };
|
||||
|
||||
// const [tier, year, month] = (await getSlug()).map((param) => Number(param));
|
||||
// if (!tier) return { notFound: true };
|
||||
|
||||
// const [summaries, monthsWithData] = await Promise.all([
|
||||
// plusService.getVotingSummariesByMonthAndTier({
|
||||
// tier: tier as any,
|
||||
// year,
|
||||
// month,
|
||||
// }),
|
||||
// plusService.getDistinctSummaryMonths(),
|
||||
// ]);
|
||||
|
||||
// if (!summaries.length) return { notFound: true };
|
||||
|
||||
// return {
|
||||
// props: { summaries, monthsWithData },
|
||||
// };
|
||||
// };
|
||||
|
||||
export default PlusHomePage;
|
||||
Loading…
Reference in New Issue
Block a user