Skip to content

Commit

Permalink
Add status to the query in admin emails dashboard, mentee and mentor …
Browse files Browse the repository at this point in the history
…registration - part 1
  • Loading branch information
Madhawa97 committed Sep 7, 2024
1 parent 698ab61 commit c5d4654
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 97 deletions.
2 changes: 1 addition & 1 deletion src/hooks/admin/useMentees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const fetchMentees = async ({
}: QueryFunctionContext<MenteesQueryKey, number>): Promise<MenteeResponse> => {
const [, menteeStatus, pageSize] = queryKey;
let url = `${API_URL}/admin/mentees/applications?pageNumber=${pageParam}&pageSize=${pageSize}`;
if (menteeStatus !== null || menteeStatus !== '') {
if (menteeStatus !== null && menteeStatus !== '') {
url += `&status=${menteeStatus}`;
}
const response = await axios.get(url, {
Expand Down
6 changes: 5 additions & 1 deletion src/hooks/admin/useMentors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ const updateMentorStatus = async (mentorStatus: MentorStatus) => {
return response.data;
};

export const useMentors = (categoryId: string| null, mentorStatus: string| null, pageSize = 10) => {
export const useMentors = (
categoryId: string | null,
mentorStatus: string | null,
pageSize = 10
) => {
const queryClient = useQueryClient();

const infiniteQueryOptions: UseInfiniteQueryOptions<
Expand Down
211 changes: 131 additions & 80 deletions src/pages/Dashboard/scenes/Emails/Emails.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React, { useState } from 'react';
import React, { useState, useCallback, useMemo, useEffect } from 'react';
import EmailHistory from '../../../../components/Dashboard/scenes/Emails/EmailHistory';
import { EMAILAPI_SENDER } from '../../../../constants';
import Loading from '../../../../assets/svg/Loading';
import { useEmails } from '../../../../hooks/useEmails';
import { type Mentor, type EmailData, type Mentee } from '../../../../types';
import { z } from 'zod';
import { useMentors } from '../../../../hooks/admin/useMentors';
import useMentees from '../../../../hooks/admin/useMentees';
import { ApplicationStatus } from '../../../../enums';
import { type EmailData } from '../../../../types';
import { z } from 'zod';

const EmailDataSchema = z.object({
sender: z.string(),
Expand All @@ -21,8 +20,7 @@ const Emails: React.FC = () => {
const [message, setMessage] = useState('');
const [loading, setLoading] = useState(false);
const { sendEmail } = useEmails();
const { data: mentors } = useMentors();
const { data: mentees } = useMentees();
const pageSize = 10;

const [formData, setFormData] = useState<EmailData>({
sender: EMAILAPI_SENDER,
Expand All @@ -31,6 +29,112 @@ const Emails: React.FC = () => {
body: '',
});

const [selectedGroup, setSelectedGroup] = useState('');

const {
data: mentorsData,
status: mentorsStatus,
fetchNextPage: fetchNextMentorsPage,
hasNextPage: hasNextMentorsPage,
isFetchingNextPage: isFetchingNextMentorsPage,
} = useMentors(null, null, pageSize);

const {
data: menteesData,
status: menteesStatus,
fetchNextPage: fetchNextMenteesPage,
hasNextPage: hasNextMenteesPage,
isFetchingNextPage: isFetchingNextMenteesPage,
} = useMentees(null, pageSize);

const isDataLoading =
mentorsStatus === 'pending' ||
menteesStatus === 'pending' ||
isFetchingNextMentorsPage ||
isFetchingNextMenteesPage;

useEffect(() => {
const fetchAllPages = async () => {
if (hasNextMentorsPage) {
void fetchNextMentorsPage();
}
if (hasNextMenteesPage) {
void fetchNextMenteesPage();
}
};

if (mentorsStatus === 'success' && menteesStatus === 'success') {
void fetchAllPages();
}
}, [
mentorsStatus,
menteesStatus,
fetchNextMentorsPage,
fetchNextMenteesPage,
hasNextMentorsPage,
hasNextMenteesPage,
]);

const allEmails = useMemo(() => {
const mentorEmails =
mentorsData?.map((mentor) => mentor.application.email) || [];
const menteeEmails =
menteesData?.map((mentee) => mentee.application.email) || [];
return { mentors: mentorEmails, mentees: menteeEmails };
}, [mentorsData, menteesData]);

const getEmailsByGroup = useCallback(
(group: string) => {
let emails: string[] = [];
switch (group) {
case 'allMentors':
emails = allEmails.mentors;
break;
case 'acceptedMentors':
emails =
mentorsData
?.filter((mentor) => mentor.state === 'approved')
.map((mentor) => mentor.application.email) || [];
break;
case 'pendingMentors':
emails =
mentorsData
?.filter((mentor) => mentor.state === 'pending')
.map((mentor) => mentor.application.email) || [];
break;
case 'rejectedMentors':
emails =
mentorsData
?.filter((mentor) => mentor.state === 'rejected')
.map((mentor) => mentor.application.email) || [];
break;
case 'allMentees':
emails = allEmails.mentees;
break;
case 'acceptedMentees':
emails =
menteesData
?.filter((mentee) => mentee.state === 'approved')
.map((mentee) => mentee.application.email) || [];
break;
case 'pendingMentees':
emails =
menteesData
?.filter((mentee) => mentee.state === 'pending')
.map((mentee) => mentee.application.email) || [];
break;
case 'rejectedMentees':
emails =
menteesData
?.filter((mentee) => mentee.state === 'rejected')
.map((mentee) => mentee.application.email) || [];
break;
}
return emails.length > 0 ? emails : ['No emails available'];
},
[allEmails, mentorsData, menteesData]
);

const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
Expand Down Expand Up @@ -69,74 +173,18 @@ const Emails: React.FC = () => {
};

const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
let selectedMentors: Mentor[] = [];
let selectedMentees: Mentee[] = [];
switch (e.target.value) {
case 'allMentors':
selectedMentors = mentors ?? [];
break;
case 'acceptedMentors':
selectedMentors =
mentors?.filter(
(mentor) => mentor.state === ApplicationStatus.APPROVED
) ?? [];
break;
case 'pendingMentors':
selectedMentors =
mentors?.filter(
(mentor) => mentor.state === ApplicationStatus.PENDING
) ?? [];
break;
case 'rejectedMentors':
selectedMentors =
mentors?.filter(
(mentor) => mentor.state === ApplicationStatus.REJECTED
) ?? [];
break;
case 'allMentees':
selectedMentees = mentees ?? [];
break;
case 'acceptedMentees':
selectedMentees =
mentees?.filter(
(mentee) => mentee.state === ApplicationStatus.APPROVED
) ?? [];
break;
case 'pendingMentees':
selectedMentees =
mentees?.filter(
(mentee) => mentee.state === ApplicationStatus.PENDING
) ?? [];
break;
case 'rejectedMentees':
selectedMentees =
mentees?.filter(
(mentee) => mentee.state === ApplicationStatus.REJECTED
) ?? [];
break;
default:
}

const selectedMentorEmails = selectedMentors
? selectedMentors.map((mentor) => mentor.application.email)
: [];

const selectedMenteeEmails = selectedMentees
? selectedMentees.map((mentee) => mentee.application.email)
: [];

setFormData((prevState) => {
const recipients = [...selectedMentorEmails, ...selectedMenteeEmails];
return {
...prevState,
recipients:
recipients.length > 0 ? recipients : ['No emails available'],
};
});
const group = e.target.value;
setSelectedGroup(group);
const emails = getEmailsByGroup(group);
setFormData((prevState) => ({
...prevState,
recipients: emails,
}));
};

return (
<div>
{isDataLoading && <div>Loading all data...</div>}
<div className="container mx-auto p-4 bg-white max-h-[800px] overflow-y-auto min-h-full min-w-full">
<div className="flex items-center space-x-4">
<h1 className="text-2xl font-medium my-4">Send Emails</h1>
Expand Down Expand Up @@ -186,6 +234,7 @@ const Emails: React.FC = () => {
<select
className="mt-4 block w-full p-3 rounded-md border-gray-500 shadow-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500 text-gray-700"
onChange={handleSelectChange}
value={selectedGroup}
>
<option value="">Select recipient group</option>
<option value="allMentors">All Mentors</option>
Expand All @@ -209,13 +258,17 @@ const Emails: React.FC = () => {
Rejected Mentees
</option>
</select>
<textarea
name="recipients"
value={formData.recipients.join(',')}
onChange={handleRecipientsChange}
placeholder="Enter recipient emails, separated by commas"
className="mt-1 px-4 py-2 block w-full rounded-md border-gray-300 shadow-sm"
/>
{isDataLoading ? (
<div className="mt-2">Loading emails...</div>
) : (
<textarea
name="recipients"
value={formData.recipients.join(',')}
onChange={handleRecipientsChange}
placeholder="Enter recipient emails, separated by commas"
className="mt-1 px-4 py-2 block w-full rounded-md border-gray-300 shadow-sm"
/>
)}
</label>
<label className="block">
<span className="text-gray-700">Body:</span>
Expand All @@ -234,9 +287,7 @@ const Emails: React.FC = () => {
className="mt-4 x-6 py-2 bg-blue-500 text-white rounded hover:bg-blue-700 cursor-pointer"
>
<div className="flex justify-center items-center h-5 px-6 py-2">
<>
<Loading />
</>
<Loading />
</div>
</button>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const MentorApplications: React.FC = () => {
error: categoriesError,
fetchNextPage: fetchNextCategories,
hasNextPage: hasNextCategoriesPage,
} = useCategories(100);
} = useCategories(pageSize);

useEffect(() => {
if (inView && hasNextPage) {
Expand Down
36 changes: 28 additions & 8 deletions src/pages/MenteeRegistration/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { useMutation } from '@tanstack/react-query';
import axios, { AxiosError } from 'axios';
import { ChangeEvent, useState } from 'react';
import { ChangeEvent, useEffect, useState } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { Link, useParams } from 'react-router-dom';

Expand All @@ -11,7 +11,7 @@ import { API_URL } from '../../constants';
import useProfile from '../../hooks/useProfile';
import { usePublicMentors } from '../../hooks/usePublicMentors';
import { MenteeApplicationSchema } from '../../schemas';
import { MenteeApplication } from '../../types';
import { MenteeApplication, Mentor } from '../../types';

const steps = [
{
Expand Down Expand Up @@ -48,7 +48,16 @@ const MenteeRegistration: React.FC = () => {
isUndergrad: true,
},
});
const { error: mentorsError, data: mentors } = usePublicMentors(null);
const [allMentors, setAllMentors] = useState<Mentor[]>([]);

const {
data,
fetchNextPage,
hasNextPage,
// isFetchingNextPage,
// status: mentorsStatus,
} = usePublicMentors(null, 10);

const [currentStep, setCurrentStep] = useState(0);
const [image, setImage] = useState<File | null>(null);
const [profilePic, setProfilePic] = useState(user?.image_url);
Expand Down Expand Up @@ -131,6 +140,17 @@ const MenteeRegistration: React.FC = () => {
},
});

useEffect(() => {
if (data) {
const allMentors = data.pages.flatMap((page) => page.items);
setAllMentors(allMentors);
}

if (hasNextPage) {
void fetchNextPage();
}
}, [data]);

return (
<div className="relative w-full">
<div className="text-2xl font-semibold mb-2">Become a Mentee</div>
Expand Down Expand Up @@ -333,9 +353,9 @@ const MenteeRegistration: React.FC = () => {
className="mt-1 p-2 w-1/2 border rounded-md"
{...register('mentorId')}
>
{mentors
?.filter((mentor) => mentor.availability)
.map((mentor) => (
{allMentors
?.filter((mentor: Mentor) => mentor.availability)
.map((mentor: Mentor) => (
<option key={mentor.uuid} value={mentor.uuid}>
{mentor.application.firstName}{' '}
{mentor.application.lastName}
Expand Down Expand Up @@ -392,12 +412,12 @@ const MenteeRegistration: React.FC = () => {
</p>
</>
)}
{mentorsError !== null ? (
{status === 'error' ? (
<div
className="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 "
role="alert"
>
{mentorsError.message}
{'An error occurred. Please try again later.'}
</div>
) : null}
{isApplicationError && applicationError instanceof AxiosError ? (
Expand Down
Loading

0 comments on commit c5d4654

Please sign in to comment.