Skip to content

Commit

Permalink
feat(admin): connect creating new organizations with backend
Browse files Browse the repository at this point in the history
  • Loading branch information
Rei-x committed Feb 19, 2023
1 parent 774898b commit 5b6228b
Show file tree
Hide file tree
Showing 8 changed files with 340 additions and 104 deletions.
275 changes: 200 additions & 75 deletions src/features/admin/views/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,71 @@ import { AnimatePresenceSSR } from "@/components/AnimatePresenceSSR";
import { useForm } from "@/hooks/useForm";
import { useUpload } from "@/hooks/useUpload";
import { acceptedImageTypes, maxFileSize } from "@/server/api/file/schema";
import { api, standaloneApiClient } from "@/utils/api";
import {
Button,
FormControl,
FormErrorMessage,
FormLabel,
Heading,
Input,
NumberDecrementStepper,
NumberIncrementStepper,
NumberInput,
NumberInputField,
NumberInputStepper,
Select,
Switch,
Textarea,
useToast,
VStack,
} from "@chakra-ui/react";
import { motion } from "framer-motion";
import React, { useState } from "react";
import React from "react";
import slugify from "slugify";
import { z } from "zod";
import { Layout } from "../components/Layout";

const departments = [
"W1",
"W2",
"W3",
"W4",
"W5",
"W6",
"W7",
"W8",
"W9",
"W10",
"W11",
"W12",
"W1 - Wydział Architektury",
"W2 - Wydział Budownictwa Lądowego i Wodnego",
"W3 - Wydział Chemiczny",
"W4 - Wydział Informatyki i Telekomunikacji",
"W5 - Wydział Elektryczny",
"W6 - Wydział Geoinżynierii, Górnictwa i Geologii",
"W7 - Wydział Inżynierii Środowiska",
"W8 - Wydział Zarządzania",
"W9 - Wydział Mechaniczno-Energetyczny",
"W10 - Wydział Mechaniczny",
"W11 - Wydział Podstawowych Problemów Techniki",
"W12 - Wydział Elektroniki, Fotoniki i Mikrosystemów",
"W13 - Wydział Matematyki",
"FLG - Filia W Legnicy",
"FJG - Filia W Jeleniej Górze",
"FWB - Filia w Wałbrzychu",
] as const;

const schema = z.object({
email: z.string().email(),
addManualy: z.boolean().default(false),
name: z.string().default(""),
residence: z.enum(departments).default("W1"),
foundationDate: z.date().default(new Date()),
description: z.string().default(""),
long_description: z.string().optional().default(""),
number_of_users: z.number().optional().default(0),
const organisationTypes = [
"Agenda Kultury",
"Koło Naukowe",
"Media Studenckie",
"Organizacja Studencka",
"Strategiczne Koło Naukowe",
"Samorząd Studencki",
] as const;

const addManuallySchema = z.object({
email: z
.string()
.email("Niepoprawny email")
.refine(
async (value) =>
!(await standaloneApiClient.users.doesExist.query({ email: value })),
{
message: "Użytkownik o podanym emailu już istnieje",
}
),
addManually: z.literal(true),
name: z.string().min(1, "Za krótka nazwa").max(100, "Za długa nazwa"),
type: z.enum(organisationTypes),
department: z.enum(departments).optional(),
description: z.string().min(1, "Za krótki opis").max(200, "Za długi opis"),
longDescription: z.string().max(6000, "Za długi opis").optional(),
logo: z
.instanceof(typeof FileList !== "undefined" ? FileList : Array)
.superRefine((value, ctx) => {
Expand All @@ -62,33 +80,112 @@ const schema = z.object({
});
}
}
}),
})
.optional(),
});

const schema = z.discriminatedUnion("addManually", [
z
.object({
addManually: z.literal(false),
})
.merge(
addManuallySchema.pick({
email: true,
})
),
addManuallySchema,
]);

export const CreatePage = () => {
const {
register,
handleSubmit,
reset,
watch,
formState: { errors, isSubmitting },
} = useForm({
schema,
mode: "onTouched",
});
const toast = useToast({
status: "success",
});
const [showAdditionalInfo, setShowAdditionalInfo] = useState(false);
const { uploadAsync } = useUpload();
const addOrganization = api.organizations.create.useMutation();
const addOrganizationByEmail = api.organizations.createByEmail.useMutation();

const addManually = watch("addManually");

return (
<Layout>
<Heading mb={4}>Stwórz organizacje</Heading>
<form
onSubmit={handleSubmit(async (data) => {
if (!data.addManually) {
try {
await addOrganizationByEmail.mutateAsync({
email: data.email,
});

toast({
status: "success",
title: "Dodano użytkownika",
description: `Użytkownik ${data.email} został dodany`,
});
reset();
} catch (e) {
console.error(e);

toast({
status: "error",
title: "Błąd podczas dodawania użytkownika",
description: `Nie udało się dodać użytkownika (więcej informacji w konsoli)`,
});
}

return;
}

let logoUrl: string | undefined;

if (data.logo instanceof FileList && data.logo[0]) {
try {
await uploadAsync(data.logo[0]);
const { url } = await uploadAsync(data.logo[0]);
logoUrl = url;
} catch (e) {
console.error(e);

toast({
title: "Organizacja została dodana",
status: "error",
title: "Błąd podczas dodawania organizacji",
description: `Nie udało się dodać organizacji (więcej informacji w konsoli)`,
});

return;
}
}

if (data.addManually) {
try {
await addOrganization.mutateAsync({
name: data.name,
email: data.email,
type: data.type,
department: data.department,
slug: slugify(data.name),
description: data.description,
longDescription: data.longDescription,
logoUrl,
});

toast({
status: "success",
title: "Dodano organizację",
description: `Organizacja ${data.name} została dodana`,
});

reset();
} catch (e) {
console.error(e);

Expand All @@ -105,29 +202,22 @@ export const CreatePage = () => {
<FormControl isRequired isInvalid={errors.email !== undefined} mb={4}>
<FormLabel>Email organizacji</FormLabel>
<Input
{...register("email")}
{...register("email", {
validate: {},
})}
variant=""
placeholder="Email organizacji"
/>
<FormErrorMessage>
{errors.email?.message && "Niepoprawny email"}
</FormErrorMessage>
<FormErrorMessage>{errors.email?.message}</FormErrorMessage>
</FormControl>
<FormControl display="flex" alignItems="center" pb={4}>
<FormLabel htmlFor="additional-info" mb="0">
Czy chcesz sam(a) uzupełniać dane?
</FormLabel>
<Switch
{...register("addManualy")}
id="additional-info"
checked={showAdditionalInfo}
onChange={(e) => {
setShowAdditionalInfo(e.target.checked);
}}
/>
<Switch {...register("addManually")} id="additional-info" />
</FormControl>
<AnimatePresenceSSR mode="wait">
{showAdditionalInfo ? (
{addManually ? (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
Expand All @@ -141,20 +231,23 @@ export const CreatePage = () => {
}}
>
<VStack align="start" mt={2} mb={6} w="100%">
<FormControl isRequired isInvalid={errors.name !== undefined}>
<FormControl
isRequired
isInvalid={"name" in errors && errors.name !== undefined}
>
<FormLabel>Nazwa organizacji</FormLabel>
<Input
{...register("name")}
variant=""
placeholder="Nazwa organizacji"
/>
<FormErrorMessage>
{errors.name?.message &&
"Nieprawidłowa nazwa organizacji"}{" "}
123
{"name" in errors && errors.name?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.logo !== undefined}>
<FormControl
isInvalid={"logo" in errors && errors.logo !== undefined}
>
<FormLabel>Logo</FormLabel>
<Input
{...register("logo")}
Expand All @@ -172,57 +265,89 @@ export const CreatePage = () => {
},
}}
/>
<FormErrorMessage>{errors.logo?.message}</FormErrorMessage>
<FormErrorMessage>
{"logo" in errors && errors.logo?.message}
</FormErrorMessage>
</FormControl>
<FormControl
isRequired
isInvalid={errors.residence !== undefined}
isInvalid={"type" in errors && errors.type !== undefined}
>
<FormLabel>Wydział</FormLabel>
<Select {...register("residence")} variant="">
{departments.map((department) => (
<option key={department} value={department}>
{department}
<FormLabel>Typ</FormLabel>
<Select {...register("type")} variant="">
{organisationTypes.map((type) => (
<option key={type} value={type}>
{type}
</option>
))}
</Select>
<FormErrorMessage>
{errors.residence?.message && "Nieprawidłowy wydział"}
{"type" in errors && errors.type?.message}
</FormErrorMessage>
</FormControl>
<FormControl isRequired>
<FormLabel>Krótki opis</FormLabel>
<AnimatePresenceSSR mode="wait">
{watch("type") === "Koło Naukowe" ? (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
exit={{ opacity: 0, height: 0 }}
transition={{
type: "spring",
duration: 1,
}}
style={{
width: "100%",
}}
>
<FormControl
isRequired
isInvalid={
"department" in errors &&
errors.department !== undefined
}
>
<FormLabel>Wydział/Filia</FormLabel>
<Select {...register("department")} variant="">
{departments.map((department) => (
<option key={department} value={department}>
{department}
</option>
))}
</Select>
<FormErrorMessage>
{"department" in errors &&
errors.department?.message &&
"Nieprawidłowy wydział/filia"}
</FormErrorMessage>
</FormControl>
</motion.div>
) : null}
</AnimatePresenceSSR>
<FormControl
isRequired
isInvalid={
"description" in errors &&
errors.description !== undefined
}
>
<FormLabel>Krótki opis (maksymalnie 200 znaków)</FormLabel>
<Textarea
{...register("description")}
variant=""
placeholder="Opis"
/>
<FormErrorMessage>
{errors.description?.message && "Nieprawidłowy opis"}
{"description" in errors && errors.description?.message}
</FormErrorMessage>
</FormControl>
<FormControl>
<FormLabel>Długi opis</FormLabel>
<Textarea
{...register("long_description")}
{...register("longDescription")}
variant=""
placeholder="Opis"
/>
</FormControl>
<FormControl>
<FormLabel>Liczba członków</FormLabel>
<NumberInput variant="">
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<FormErrorMessage>
{errors.number_of_users?.message &&
"Nieprawidłowa ilość członków"}
</FormErrorMessage>
</FormControl>
</VStack>
</motion.div>
) : null}
Expand Down
Loading

0 comments on commit 5b6228b

Please sign in to comment.