Skip to content

Commit

Permalink
Added BulkRatingModal
Browse files Browse the repository at this point in the history
  • Loading branch information
shema-surge committed Oct 30, 2024
1 parent df093d2 commit 2f3b115
Show file tree
Hide file tree
Showing 20 changed files with 4,302 additions and 918 deletions.
61 changes: 61 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
"url-polyfill": "^1.1.12",
"vite": "^5.4.7",
"vite-tsconfig-paths": "^5.0.1",
"xlsx": "^0.18.5",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
52 changes: 52 additions & 0 deletions src/Mutations/Ratings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,55 @@ export const REJECT_RATING = gql`
rejectRating(user: $user, sprint: $sprint)
}
`;

export const GET_RATINGS_BY_USER_COHORT = gql`
query getRatingsByUserCohort($orgToken: String!){
getRatingsByUserCohort(orgToken: $orgToken){
id
sprint
}
}
`

export const ADD_RATINGS_BY_FILE = gql`
mutation addRatingsByFile($file: Upload!, $sprint: Int!, $orgToken: String!){
addRatingsByFile(file: $file, sprint: $sprint orgToken: $orgToken){
NewRatings {
user {
email
}
sprint
phase
quality
quantity
professional_Skills
feedbacks {
sender {
email
}
content
createdAt
}
cohort {
name
}
}
RejectedRatings{
email
quantity
quality
professional_skills
feedBacks
}
UpdatedRatings {
quantity
quality
professional_Skills
feedbacks {
content
}
oldFeedback
}
}
}
`
12 changes: 12 additions & 0 deletions src/Mutations/teamMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,15 @@ export const DeleteTeam = gql`
}
`;

export const GET_TEAMS_BY_USER_ROLE = gql`
query getTeamsByUserRole($orgToken: String!) {
getTeamsByUserRole(orgToken: $orgToken){
id
name
members {
email
role
}
}
}
`
230 changes: 230 additions & 0 deletions src/components/BulkRatingModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { useLazyQuery, useMutation } from "@apollo/client"
import React, { useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import * as XLSX from "xlsx"
import { ADD_RATINGS_BY_FILE, GET_RATINGS_BY_USER_COHORT } from "../Mutations/Ratings"
import { toast } from "react-toastify"
import { GET_TEAMS_BY_USER_ROLE } from "../Mutations/teamMutation"

type BulkRatingModalProps = {
bulkRateModal: boolean,
setBulkRateModal: React.Dispatch<React.SetStateAction<boolean>>
}

type AddRatingsByFileFormData = {
sprint: string,
file: File | null,
}

const BulkRatingModal = ({ bulkRateModal, setBulkRateModal }: BulkRatingModalProps) => {
const { t } = useTranslation()
const [getRatingsByUserCohort, { data: ratings, loading: loadingRatings, error: ratingsError }] = useLazyQuery(GET_RATINGS_BY_USER_COHORT, {
variables: {
orgToken: localStorage.getItem('orgToken')
},
fetchPolicy: 'network-only',
})
const [getTeamsByUserRole, {data: teams, loading: loadingTeams, error: teamsError}] = useLazyQuery(GET_TEAMS_BY_USER_ROLE, {
variables: {
orgToken: localStorage.getItem('orgToken')
},
fetchPolicy: 'network-only',
})
const [addRatingsByFile, { data: bulkRatings, loading: loadingBulkRatings, error: bulkRatingsError }] = useMutation(ADD_RATINGS_BY_FILE)
const [formData, setFormData] = useState<AddRatingsByFileFormData>({
sprint: '',
file: null
})
const [selectedTeam, setSelectedTeam] = useState<string>('')

const saveRatings = async (e: React.FormEvent) => {
try {
e.preventDefault()
if(!formData.sprint) throw new Error("Please select a sprint")
if(!formData.file) throw new Error("Please select a file")
await addRatingsByFile({
variables: {
file: formData.file,
sprint: parseInt(formData.sprint),
orgToken: localStorage.getItem('orgToken')
},
})
getRatingsByUserCohort()
toast.success("Rating completed successfully")
} catch (err: any) {
toast.error(err?.message)
}
}

const downloadTeamFile = async(e: any)=>{
try{
if(selectedTeam === '') throw new Error("No Team was selected")
const team = teams.getTeamsByUserRole.find((team:any)=>team.id === selectedTeam)
const rows: any = []
team.members.forEach((member: any) => {
console.log(member)
if (member.role === "trainee") {
rows.push({
email: member.email,
quantity: '',
quality: '',
professional_skills: '',
feedBacks: ''
})
}
})
const workSheet = rows.length ? XLSX.utils.json_to_sheet(rows) : XLSX.utils.json_to_sheet([{
email: '',
quantity: '',
quality: '',
professional_skills:'',
feedBacks: ''
}])
const workBook = XLSX.utils.book_new()
workSheet["!cols"] = [ { wch: 20 } ]
XLSX.utils.book_append_sheet(workBook, workSheet,"ratings")
XLSX.writeFile(workBook, `${team.name.replace(' ','')}_Ratings.xlsx`)
}catch(err: any){
toast.error(err?.message)
}
}

useEffect(() => {
getRatingsByUserCohort()
getTeamsByUserRole()
}, [])

return (
<div className={`${bulkRateModal ? "block" : "hidden"} h-screen w-screen z-20 bg-black bg-opacity-30 backdrop-blur-sm fixed top-0 left-0 flex items-center justify-center px-4`}>
<div className="w-full p-4 pb-8 bg-indigo-100 rounded-lg dark:bg-dark-bg sm:w-3/4 xl:w-4/12">
<div className="flex flex-wrap items-center justify-center w-full card-title">
<h3 className="w-11/12 text-sm font-bold text-center dark:text-white">
{t('Bulk Rating')}
</h3>
<hr className="w-full my-3 border-b bg-primary" />
</div>
<div>
<form data-testid="bulk-rating-form" className="flex flex-col gap-5" onSubmit={saveRatings}>
<div className="flex flex-col gap-1">
<label>Choose a sprint</label>
<select data-testid="select-sprint" className="p-2 text-black dark:text-white rounded-lg bg-white dark:bg-dark border-2 border-primary"
defaultValue={""}
onChange={(e) => {
e.preventDefault()
setFormData({ ...formData, sprint: e.target.value })
}}
>
<option>Choose a sprint</option>
{
ratings && !ratings.getRatingsByUserCohort.length ?
<option data-testid="sprint-default-option" value={1}>Sprint 1</option>
: ''
}
{
ratings && ratings.getRatingsByUserCohort.length ?
[...ratings.getRatingsByUserCohort].map((rating: any) =>
<option data-testid={`sprint-option-${rating.id}`} key={rating.id} value={rating.sprint}>Sprint {rating.sprint}</option>
)
: ''
}
{
ratings && ratings.getRatingsByUserCohort.length ?
<option data-testid="sprint-new-option" value={[...ratings.getRatingsByUserCohort].pop().sprint+1}>Sprint {[...ratings.getRatingsByUserCohort].pop().sprint+1}</option>
: ''
}
{
loadingRatings ?
<option data-testid="sprint-loading-option">Loading...</option>
: ''
}
{
ratingsError ?
<option data-testid="sprint-error-option">No sprints found...</option>
: ''
}
</select>
</div>
<div className="flex items-center justify-between">
<input
data-testid="file-input"
className="w-1/2 h-full bg-gray-600 rounded-md"
type="file"
onChange={(e) => {
const file = e.target.files?.[0]
setFormData({ ...formData, file: file ? file : null })
}}
accept=".xlsx, .xls"
>
</input>
<div className="flex gap-2">
<select data-testid="select-team" className="p-2 text-sm text-black dark:text-white rounded-lg bg-white dark:bg-dark border-2 border-primary" defaultValue={""} onChange={(e)=>setSelectedTeam(e.target.value)}>
<option data-testid="team-default-option">Choose a team</option>
{
teams && teams.getTeamsByUserRole.length > 0 ?
teams.getTeamsByUserRole.map((team: any)=><option data-testid={`team-option-${team.id}`} key={team.id} value={team.id}>{team.name}</option>)
: ''
}
{
loadingTeams ?
<option>Loading...</option>
: ''
}
{
teamsError ?
<option>No teams found...</option>
: ''
}
</select>
<button data-testid="download-button" type="button" onClick={downloadTeamFile} className="p-3 text-white rounded-lg bg-green-500 text-sm font-serif font-semibold">Download</button>
</div>
</div>

<div>
{
bulkRatings && bulkRatings.addRatingsByFile.RejectedRatings.length > 0 ?
<div className="my-1 overflow-x-auto">
<table className="table-fixed min-w-full">
<caption className="caption-top text-left my-2">
Rejected Ratings
</caption>
<thead className="border-b bg-neutral-700 border-neutral-400">
<tr>
<th scope="col" className="text-left py-4 px-2">Email</th>
<th scope="col" className="text-left py-4 px-2">Quantity</th>
<th scope="col" className="text-left py-4 px-2">Quality</th>
<th scope="col" className="text-left py-4 px-2">Professional_Skills</th>
<th scope="col" className="text-left py-4 px-2">Feedback</th>
</tr>
</thead>
<tbody>
{bulkRatings.addRatingsByFile?.RejectedRatings.map((rating: any, index: number) =>
<tr key={index} className="text-red-400">
<td className="text-left py-1 px-2">{rating.email ? rating.email : "null"}</td>
<td className="text-left py-1 px-2">{rating.quantity ? rating.quantity : "null"}</td>
<td className="text-left py-1 px-2">{rating.quality ? rating.quality : "null"}</td>
<td className="text-left py-1 px-2">{rating.professional_skills ? rating.professional_skills : "null"}</td>
<td className="text-left py-1 px-2">{rating.feedBacks ? rating.feedBacks : "null"}</td>
</tr>
)}
</tbody>
</table>
</div>
: ''
}
</div>
<div className="flex justify-between w-full">
<button className="w-[40%] md:w-1/4 p-3 text-white rounded-lg bg-primary text-sm font-serif font-semibold" type="button" onClick={() => setBulkRateModal(false)}>
Cancel
</button>
<button className="w-[40%] md:w-1/4 p-3 text-white rounded-lg bg-primary text-sm font-serif font-semibold" type="submit">
Save
</button>
</div>
</form>
</div>
</div>
</div>
)
}

export default BulkRatingModal
Loading

0 comments on commit 2f3b115

Please sign in to comment.