add skill level selector

This commit is contained in:
Brandon Egger 2023-06-04 23:03:37 -05:00
parent 8810e03894
commit d4cd046c4b
3 changed files with 155 additions and 40 deletions

View File

@ -13,7 +13,7 @@ const AdminBarLayout = ({
return (
<div className="relative">
{data?.user.role === Role.ADMIN ? (
<div className="flex sticky left-0 right-0 top-[71px] z-10 mx-auto mb-3 mt-[15px] max-w-4xl flex-row justify-between rounded-xl border border-neutral-600 bg-red-300 drop-shadow-xl sm:mb-6">
<div className="sticky left-0 right-0 top-[71px] z-10 mx-auto mb-3 mt-[15px] flex max-w-4xl flex-row justify-between rounded-xl border border-neutral-600 bg-red-300 drop-shadow-xl sm:mb-6">
<h1 className="rounded-lg px-4 py-2 font-semibold text-black">
Admin Mode
</h1>

View File

@ -1,10 +1,12 @@
import { PaymentType, type AuditoryResource } from "@prisma/client";
import { PaymentType, type AuditoryResource, SkillLevel } from "@prisma/client";
import Image from "next/image";
import { PencilSquareIcon } from "@heroicons/react/24/solid";
import {
MultiSelector,
MultiSelectorContext,
MultiSelectorMany,
MultiSelectorOption,
SelectedManyContext,
SelectedUniqueContext,
} from "../../forms/selectors";
import { InfoInputLine } from "~/components/forms/textInput";
import { PriceIcon } from "~/prices/Icons";
@ -71,8 +73,8 @@ const PaymentTypeOption = ({
}) => {
return (
<MultiSelectorOption value={type}>
<MultiSelectorContext.Consumer>
{({ selected }) => (
<SelectedUniqueContext.Consumer>
{(selected) => (
<div
className={
(selected === type ? "bg-stone-800" : "bg-white") +
@ -92,7 +94,43 @@ const PaymentTypeOption = ({
</span>
</div>
)}
</MultiSelectorContext.Consumer>
</SelectedUniqueContext.Consumer>
</MultiSelectorOption>
);
};
const SkillLevelOption = ({
type,
label,
}: {
type: SkillLevel;
label: string;
}) => {
return (
<MultiSelectorOption value={type}>
<SelectedManyContext.Consumer>
{(selected) => (
<div
className={
(selected.includes(type.toString())
? "bg-stone-800"
: "bg-white") +
" flex flex-row space-x-2 whitespace-nowrap rounded-xl border border-neutral-400 px-2 py-1"
}
>
<span
className={
(selected.includes(type.toString())
? "text-white"
: "text black") +
" my-auto inline-block whitespace-nowrap text-sm"
}
>
{label}
</span>
</div>
)}
</SelectedManyContext.Consumer>
</MultiSelectorOption>
);
};
@ -129,24 +167,31 @@ const ResourceSummarySubForm = ({
</span>
</div>
</div>
<div>
<MultiSelector
label="Price Category"
defaultValue={
resource?.payment_options.toString() ?? PaymentType.FREE.toString()
}
>
<PaymentTypeOption type={PaymentType.FREE} label="Free" />
<PaymentTypeOption
type={PaymentType.SUBSCRIPTION_MONTHLY}
label="Monthly Subscription"
/>
<PaymentTypeOption
type={PaymentType.SUBSCRIPTION_WEEKLY}
label="Weekly Subscription"
/>
</MultiSelector>
</div>
<MultiSelector
label="Price Category"
defaultValue={
resource?.payment_options.toString() ?? PaymentType.FREE.toString()
}
>
<PaymentTypeOption type={PaymentType.FREE} label="Free" />
<PaymentTypeOption
type={PaymentType.SUBSCRIPTION_MONTHLY}
label="Monthly Subscription"
/>
<PaymentTypeOption
type={PaymentType.SUBSCRIPTION_WEEKLY}
label="Weekly Subscription"
/>
</MultiSelector>
<MultiSelectorMany
label="Skill Level"
defaultValues={resource?.skill_levels ?? []}
>
<SkillLevelOption type={SkillLevel.BEGINNER} label="beginner" />
<SkillLevelOption type={SkillLevel.INTERMEDIATE} label="intermediate" />
<SkillLevelOption type={SkillLevel.ADVANCED} label="advanced" />
</MultiSelectorMany>
</div>
);
};

View File

@ -1,12 +1,68 @@
import { createContext, useContext, useState } from "react";
// Define contexts
const MultiSelectorContext = createContext({
selected: "",
const SelectorContext = createContext<{
type: "one" | "many";
updateCallback: (_value: string) => void;
}>({
type: "one",
updateCallback: (_value: string) => {
return;
},
});
const SelectedUniqueContext = createContext<string>("");
const SelectedManyContext = createContext<string[]>([]);
function MultiSelectorMany<T extends { toString: () => string }>({
label,
defaultValues,
children,
}: {
label: string;
defaultValues: T[];
children: undefined | JSX.Element | JSX.Element[];
}) {
const [selected, setSelected] = useState<string[]>(
defaultValues.map((value) => {
return value.toString();
})
);
const updateCallback = (value: string) => {
if (selected.includes(value)) {
setSelected(
selected.filter((selectedValue) => {
return selectedValue !== value;
})
);
return;
}
setSelected([value, ...selected]);
};
return (
<SelectorContext.Provider value={{ type: "many", updateCallback }}>
<SelectedManyContext.Provider value={selected}>
<div className="flex flex-col">
<label className="text-md block font-semibold">{label}</label>
<span className="block text-sm italic text-neutral-400">
Select all that apply
</span>
<input
readOnly
type="text"
className="hidden"
value={selected ?? ""}
/>
<div className="flex mt-2 flex-row space-x-2 overflow-x-auto">
{children}
</div>
</div>
</SelectedManyContext.Provider>
</SelectorContext.Provider>
);
}
function MultiSelector<T extends { toString: () => string }>({
label,
@ -20,20 +76,27 @@ function MultiSelector<T extends { toString: () => string }>({
const [selected, setSelected] = useState<string>(defaultValue.toString());
return (
<MultiSelectorContext.Provider
value={{ selected, updateCallback: setSelected }}
<SelectorContext.Provider
value={{ type: "many", updateCallback: setSelected }}
>
<div className="flex flex-col">
<label className="text-md block font-semibold">{label}</label>
<span className="block text-sm italic text-neutral-400">
Select one from below
</span>
<input readOnly type="text" className="hidden" value={selected ?? ""} />
<div className="mt-2 flex flex-row space-x-2 overflow-x-auto">
{children}
<SelectedUniqueContext.Provider value={selected}>
<div className="flex flex-col">
<label className="text-md block font-semibold">{label}</label>
<span className="block text-sm italic text-neutral-400">
Select one from below
</span>
<input
readOnly
type="text"
className="hidden"
value={selected ?? ""}
/>
<div className="flex mt-2 flex-row space-x-2 overflow-x-auto">
{children}
</div>
</div>
</div>
</MultiSelectorContext.Provider>
</SelectedUniqueContext.Provider>
</SelectorContext.Provider>
);
}
@ -44,7 +107,7 @@ function MultiSelectorOption<T extends { toString: () => string }>({
value: T;
children: undefined | JSX.Element | JSX.Element[];
}) {
const { updateCallback } = useContext(MultiSelectorContext);
const { updateCallback } = useContext(SelectorContext);
return (
<button
@ -58,4 +121,11 @@ function MultiSelectorOption<T extends { toString: () => string }>({
);
}
export { MultiSelectorContext, MultiSelector, MultiSelectorOption };
export {
SelectedUniqueContext,
SelectorContext,
SelectedManyContext,
MultiSelectorMany,
MultiSelector,
MultiSelectorOption,
};