user selector ver 1

This commit is contained in:
Kalle (Sendou) 2020-12-18 17:09:35 +02:00
parent b063675ee3
commit cb398c8d07
7 changed files with 173 additions and 13 deletions

View File

@ -12,14 +12,16 @@ interface SelectProps {
options?:
| OptionsType<{
label: string;
value: string;
value: any;
data?: any;
}>
| GroupedOptionsType<{
label: string;
value: string;
data?: any;
}>;
width?: string;
value: ValueType<OptionTypeBase, boolean>;
value?: ValueType<OptionTypeBase, boolean>;
setValue: (value: any) => void;
autoFocus?: boolean;
components?: Partial<SelectComponents<OptionTypeBase, boolean>>;
@ -37,13 +39,13 @@ const MySelect: React.FC<SelectProps> = ({
components,
value,
setValue,
isClearable,
autoFocus,
isMulti,
isLoading,
isDisabled,
isSearchable,
menuIsOpen,
isClearable = false,
autoFocus = false,
isMulti = false,
isLoading = false,
isDisabled = false,
isSearchable = false,
menuIsOpen = false,
hideMenuBeforeTyping,
}) => {
const {

View File

@ -12,6 +12,7 @@ const UserAvatar: React.FC<Props & AvatarProps> = ({
isSmall,
...props
}) => {
console.log({ user });
return (
<Avatar
name={user.username}

View File

@ -0,0 +1,96 @@
import { Box, Center, Flex } from "@chakra-ui/react";
import { Trans } from "@lingui/macro";
import { GetAllUsersLeanData } from "prisma/queries/getAllUsersLean";
import { components } from "react-select";
import useSWR from "swr";
import MySelect from "./MySelect";
import UserAvatar from "./UserAvatar";
interface SingleSelectorProps {
value?: number;
setValue: (value: number) => void;
isMulti: false | undefined;
maxMultiCount: undefined;
}
interface MultiSelectorProps {
value: number[];
setValue: (value: number[]) => void;
isMulti: true;
maxMultiCount: number;
}
const UserSelector: React.FC<SingleSelectorProps | MultiSelectorProps> = ({
value,
setValue,
isMulti,
maxMultiCount,
}) => {
const { data } = useSWR<GetAllUsersLeanData>("/api/users");
const singleOption = (props: any) => {
return (
<components.Option {...props}>
<Flex alignItems="center">
<Box mr="0.5em">
<UserAvatar user={props.data.data} />
</Box>
{props.label}
</Flex>
</components.Option>
);
};
return (
<MySelect
options={getUsersArray().map((user) => ({
label: `${user.username}#${user.discriminator}`,
value: "" + user.id,
data: user,
}))}
setValue={(newValue) => {
if (isMulti) {
setValue(newValue.map((value: string) => parseInt(value)));
} else {
setValue(newValue ? parseInt(newValue) : newValue);
}
}}
isSearchable
isMulti={isMulti}
components={{
IndicatorSeparator: () => null,
Option: singleOption,
NoOptionsMessage: () => (
<Center p={4}>
<>
{isTooManyItems() ? (
<Trans>Only {maxMultiCount} users allowed</Trans>
) : (
<Trans>No results with this filter</Trans>
)}
</>
</Center>
),
}}
hideMenuBeforeTyping
/>
);
function getUsersArray() {
console.log({ value, maxMultiCount });
if (!data) return [];
if (isTooManyItems()) {
return [];
}
return data;
}
function isTooManyItems() {
return (
maxMultiCount && Array.isArray(value) && maxMultiCount <= value.length
);
}
};
export default UserSelector;

View File

@ -1,4 +1,5 @@
import { Box, Flex } from "@chakra-ui/react";
import { Box, Center, Flex } from "@chakra-ui/react";
import { Trans } from "@lingui/macro";
import { useLingui } from "@lingui/react";
import {
salmonRunWeapons,
@ -44,7 +45,7 @@ const WeaponSelector: React.FC<SingleSelectorProps | MultiSelectorProps> = ({
const { i18n } = useLingui();
const singleOption = (props: any) => (
<components.Option {...props}>
<Flex alignItems="center" color={props.isFocused ? "black" : undefined}>
<Flex alignItems="center">
<Box mr="0.5em">
<WeaponImage size={32} name={props.value} />
</Box>
@ -71,6 +72,17 @@ const WeaponSelector: React.FC<SingleSelectorProps | MultiSelectorProps> = ({
components={{
IndicatorSeparator: () => null,
Option: singleOption,
NoOptionsMessage: () => (
<Center p={4}>
<>
{isTooManyItems() ? (
<Trans>Only {maxMultiCount} weapons allowed</Trans>
) : (
<Trans>No results with this filter</Trans>
)}
</>
</Center>
),
}}
autoFocus={autoFocus}
isDisabled={isDisabled}
@ -93,7 +105,7 @@ const WeaponSelector: React.FC<SingleSelectorProps | MultiSelectorProps> = ({
}
function getWeaponArray() {
if (maxMultiCount && maxMultiCount <= (value ?? []).length) return [];
if (isTooManyItems()) return [];
if (pool === "WITH_ALTS") return weaponsWithHeroCategorized;
if (pool === "SALMON_RUN")
return weaponsWithHeroCategorized.map((category) => ({
@ -108,6 +120,10 @@ const WeaponSelector: React.FC<SingleSelectorProps | MultiSelectorProps> = ({
),
}));
}
function isTooManyItems() {
return maxMultiCount && maxMultiCount <= (value ?? []).length;
}
};
export default WeaponSelector;

9
pages/api/users/index.ts Normal file
View File

@ -0,0 +1,9 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getAllUsersLean } from "prisma/queries/getAllUsersLean";
const usersHandler = async (_req: NextApiRequest, res: NextApiResponse) => {
const users = await getAllUsersLean();
res.status(200).json(users);
};
export default usersHandler;

View File

@ -17,6 +17,7 @@ import { t, Trans } from "@lingui/macro";
import { useLingui } from "@lingui/react";
import { SalmonRunRecordCategory } from "@prisma/client";
import Breadcrumbs from "components/common/Breadcrumbs";
import UserSelector from "components/common/UserSelector";
import RotationSelector from "components/sr/RotationSelector";
import Image from "next/image";
import { useState } from "react";
@ -54,7 +55,7 @@ const salmonRunCategoryToNatural = {
const AddRecordModal = () => {
const { i18n } = useLingui();
const [sending, setSending] = useState(false);
const [form, setForm] = useState<Partial<RecordFormData>>({});
const [form, setForm] = useState<Partial<RecordFormData>>({ rotationId: 1 });
return (
<Container maxWidth="75ch">
@ -124,6 +125,21 @@ const AddRecordModal = () => {
</NumberInputStepper>
</NumberInput>
<FormControl>
<FormLabel mt={4}>
<Trans>Players</Trans>
</FormLabel>
<UserSelector
value={form.userIds ?? []}
setValue={(userIds: number[]) => setForm({ ...form, userIds })}
isMulti={true}
maxMultiCount={3}
/>
<FormHelperText>
Add up to three people you played with when you got the result.
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel mt={4}>
<Trans>Links</Trans>
@ -140,6 +156,9 @@ const AddRecordModal = () => {
onChange={(e) => setForm({ ...form, links: e.target.value })}
rows={4}
resize="none"
placeholder={
"https://twitter.com/BrianTheDrumer/status/1338469066797953024\nhttps://www.youtube.com/watch?v=6evFXzxrTfU"
}
/>
</FormControl>

View File

@ -0,0 +1,17 @@
import { Prisma } from "@prisma/client";
import prisma from "prisma/client";
export type GetAllUsersLeanData = Prisma.PromiseReturnType<
typeof getAllUsersLean
>;
export const getAllUsersLean = async () =>
prisma.user.findMany({
select: {
id: true,
username: true,
discriminator: true,
discordAvatar: true,
discordId: true,
},
});