Skip to content

Commit

Permalink
Add create mentor page
Browse files Browse the repository at this point in the history
  • Loading branch information
cipick committed Aug 20, 2023
1 parent 6c0949c commit 0c4f44c
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 55 deletions.
2 changes: 1 addition & 1 deletion client/src/components/MultiSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function MultiSelect({
leaveTo="opacity-0"
afterLeave={() => setQuery("")}
>
<Combobox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
<Combobox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm z-20">
{filteredPeople.length === 0 && query !== "" ? (
<div className="relative cursor-default select-none py-2 px-4 text-gray-700">
Nu am găsit niciun domeniu similar.
Expand Down
129 changes: 90 additions & 39 deletions client/src/pages/CreateMentor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import React from "react";
import React, { useMemo } from "react";
import Section from "@/components/Section";
import Heading from "@/components/Heading";
import Input from "@/components/Input";
import Button from "@/components/Button";
import Select from "@/components/Select";
import {
useCreateMentorMutation,
useGetDimensionsQuery,
useGetProgramsQuery,
} from "@/redux/api/userApi";
import { SubmitHandler, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod/dist/zod";
import { object, string, TypeOf } from "zod";
import { LoginInput } from "@/pages/public/Login";
import { array, number, object, string, TypeOf } from "zod";
import { ErrorMessage } from "@hookform/error-message";
import MultiSelect from "@/components/MultiSelect";

const mentorSchema = object({
firstName: string(),
lastName: string(),
email: string(),
firstName: string(),
email: string().email(),
bio: string(),
expertise: string(),
dimensions: string(),
programs: string(),
dimensions: array(number()),
programs: array(number()),
});

export type MentorInput = TypeOf<typeof mentorSchema>;
Expand All @@ -33,6 +32,25 @@ const InputField = ({ label, children }) => (
</div>
);

const Input = ({ register, name, label, errors, ...rest }) => (
<div className="container mt-0 mr-auto mb-0 ml-auto pt-2 pr-4 pb-2">
<label className="block text-sm font-medium text-gray-700">{label}</label>
<div className="mt-1 mr-0 mb-0 ml-0 rounded-md shadow-sm relative">
<input
className="border focus:ring-teal-500 focus:border-teal-500
w-full h-10 block border-gray-300 shadow-sm pt-0 pr-0 pb-0 pl-4 rounded-md sm:text-sm"
{...register(name)}
{...rest}
/>
{errors && (
<div className="text-red-400 text-sm py-2">
<ErrorMessage errors={errors} name={name} />
</div>
)}
</div>
</div>
);

const CreateMentor = () => {
const { data: programs, isLoading: isLoadingPrograms } =
useGetProgramsQuery();
Expand All @@ -48,11 +66,35 @@ const CreateMentor = () => {
resolver: zodResolver(mentorSchema),
});

const onSubmitHandler: SubmitHandler<LoginInput> = (values) => {
console.log("values", values);
createMentor(values);
const onSubmitHandler: SubmitHandler<MentorInput> = (values) => {
createMentor({
...values,
role: 4,
username: values.email,
password: "temporary-password",
});
};

const programsOptions = useMemo(
() =>
programs?.map(({ id, name }) => ({
id: id,
name: name,
label: name,
})),
[programs]
);

const dimensionsOptions = useMemo(
() =>
dimensions?.map(({ id, name }) => ({
id: id,
name: name,
label: name,
})),
[dimensions]
);

return (
<div>
<Section>
Expand All @@ -64,66 +106,75 @@ const CreateMentor = () => {
<InputField label="Nume persoană resursă">
<Input
placeholder="Introdu nume persoană resursă"
{...register("lastName")}
name="lastName"
register={register}
errors={errors}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="lastName" errors={errors} />
</div>
</InputField>
<InputField label="Prenume persoană resursă">
<Input
placeholder="Introdu prenume persoană resursă"
{...register("firstName")}
name="firstName"
register={register}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="firstName" errors={errors} />
</div>
</InputField>
<InputField label="Email persoană resursă">
<Input
placeholder="Introdu email persoană resursă"
name="email"
type="email"
{...register("email")}
register={register}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="email" errors={errors} />
</div>
</InputField>
<InputField label="Descriere (bio)">
<textarea
className="block w-full rounded-md border-0 py-1.5 pl-5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-teal-600 sm:text-sm sm:leading-6"
placeholder="Adaugă o scurtă descriere a persoanei resursă"
{...register("bio")}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="bio" errors={errors} />
</div>
</InputField>
<InputField label="Arii de expertiză">
<textarea
className="block w-full rounded-md border-0 py-1.5 pl-5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-teal-600 sm:text-sm sm:leading-6"
placeholder="Descriere ariile de expertiză ale persoanei resursă"
{...register("expertise")}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="expertise" errors={errors} />
</div>
</InputField>
{!isLoadingDimensions && (
<InputField label="Specializare pe dimensiuni">
<Select
name={"dimensions"}
options={[
{
name: null,
label: "Alege toate variantele care se aplică",
},
...dimensions?.map(({ name }) => ({
name,
label: name,
})),
]}
<MultiSelect
options={dimensionsOptions}
{...register("dimensions")}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="dimensions" errors={errors} />
</div>
</InputField>
)}
{!isLoadingPrograms && (
<InputField label="Program asociat">
<Select
name={"programs"}
options={[
{
name: null,
label: "Alege toate variantele care se aplică",
},
...programs?.map(({ name }) => ({
name,
label: name,
})),
]}
<MultiSelect
options={programsOptions}
{...register("programs")}
/>
<div className="text-red-600 text-sm mt-1">
<ErrorMessage name="programs" errors={errors} />
</div>
</InputField>
)}
<div className="flex justify-end space-x-2.5 mt-10">
Expand Down
5 changes: 5 additions & 0 deletions client/src/redux/api/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
interface Role {
id: number;
type: "fdsc";
}

Expand Down Expand Up @@ -73,6 +74,10 @@ export interface Domain {
name: string;
}

export interface Program {
name: string;
}

export type Matrix = {
name: string;
quiz: {
Expand Down
7 changes: 4 additions & 3 deletions client/src/redux/api/userApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EvaluationInput } from "@/pages/Evaluation";
import { ReportInput } from "@/pages/NewReport";
import { RootState } from "@/redux/store";
import { setUser } from "../features/userSlice";
import { User, Report, Evaluation, Matrix } from "./types";
import { User, Report, Evaluation, Matrix, Program } from "./types";

const BASE_URL = import.meta.env.VITE_SERVER_ENDPOINT as string;

Expand Down Expand Up @@ -72,14 +72,15 @@ export const userApi = createApi({
},
}),
createMentor: builder.mutation<User, User>({
query() {
query(body) {
return {
method: "POST",
url: "users",
body,
};
},
}),
getPrograms: builder.query<User[], null>({
getPrograms: builder.query<Program[], null>({
query() {
return {
url: `programs`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,46 @@ const sendMailToUserWhenUserIsInvited = (to, data) =>
data
);

const sendMailToMentorWhenMentorIsInvited = (to, data) =>
strapi.plugin("email-designer").service("email").sendTemplatedEmail(
{
to,
},
{
templateReferenceId: 9,
},
data
);

module.exports = {
async beforeCreate(event) {
event.params.data.provider = "local";
event.params.data.username = event.params.data.email;
event.params.data.role = 1;
event.params.data.confirmed = true;
if (!event.params.data.role) {
event.params.data.role = 1;
}
},
async afterCreate(event) {
const { result, params } = event;

if (!params.data.password) {
if (!params.data.password || params.data.role === 4) {
const registrationToken = strapi.service("admin::token").createToken();

await strapi.plugin("users-permissions").service("user").edit(result.id, {
registrationToken,
});

try {
await sendMailToUserWhenUserIsInvited(result.email, {
ONG_NAME: result.ongName,
CODE: registrationToken,
});
if (params.data.role === 4) {
await sendMailToMentorWhenMentorIsInvited(result.email, {
CODE: registrationToken,
});
} else {
await sendMailToUserWhenUserIsInvited(result.email, {
ONG_NAME: result.ongName,
CODE: registrationToken,
});
}
} catch (e) {
console.log(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,24 @@
},
"ongName": {
"type": "string",
"required": true
"required": false
},
"ongIdentificationNumber": {
"type": "string",
"required": true,
"required": false,
"unique": true
},
"county": {
"type": "string",
"required": true
"required": false
},
"city": {
"type": "string",
"required": true
"required": false
},
"phone": {
"type": "string",
"required": true
"required": false
},
"website": {
"type": "string"
Expand Down

1 comment on commit 0c4f44c

@vercel
Copy link

@vercel vercel bot commented on 0c4f44c Aug 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

crestem-ong – ./

crestem-ong-git-main-code4romania.vercel.app
crestem-ong-code4romania.vercel.app
app.crestem.ong

Please sign in to comment.