Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(addJudgePage) create Add Judge Page #24

Merged
merged 15 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,7 @@ cargo run

## Design File

Here is the Figma design file: https://www.figma.com/file/qwBWs4i7pJMpFbcjMffDZU/Jury-(Gavel-Plus)?node-id=8%3A100&t=xYwfPwRAUeJw9jNr-1
Here is the Figma design file: https://www.figma.com/file/qwBWs4i7pJMpFbcjMffDZU/Jury-(Gavel-Plus)?node-id=8%3A100&t=xYwfPwRAUeJw9jNr-1

## Backend Routes

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"universal-cookie": "^4.0.4"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.3",
"esbuild": "^0.17.8",
"tailwindcss": "^3.2.6"
},
Expand Down
13 changes: 13 additions & 0 deletions client/src/admin/AddJudges.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import JuryHeader from '../components/JuryHeader';
import AddJudgesPanel from '../components/admin/add-judges/AddJudgesPanel';

const AddJudges = () => {
return (
<>
<JuryHeader withLogout isAdmin />
<AddJudgesPanel />
</>
);
};

export default AddJudges;
File renamed without changes.
9 changes: 0 additions & 9 deletions client/src/admin/add-judges.tsx

This file was deleted.

12 changes: 12 additions & 0 deletions client/src/components/admin/add-judges/AddJudgeStat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { twMerge } from 'tailwind-merge';

const AddJudgeStat = (props: { name: string; value: string | number; className?: string }) => {
return (
<div className={twMerge('text-center', props.className)}>
<div className="text-4xl md:text-6xl">{props.value}</div>
<div className="text-light text-lg md:text-2xl">{props.name}</div>
</div>
);
};

export default AddJudgeStat;
15 changes: 15 additions & 0 deletions client/src/components/admin/add-judges/AddJudgeStatsPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import AddJudgeStat from './AddJudgeStat';

const AddJudgeStatsPanel = () => {
return (
<div className="flex flex-col justify-evenly w-full mt-8">
<div className="flex justify-evenly basis-2/5">
<AddJudgeStat name="Active Judges" value={100} />
<AddJudgeStat name="Average Votes" value={21.2} />
<AddJudgeStat name="Average Seen" value={21.2} />
</div>
</div>
);
};

export default AddJudgeStatsPanel;
18 changes: 18 additions & 0 deletions client/src/components/admin/add-judges/AddJudgesPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AddJudgeStatsPanel from './AddJudgeStatsPanel';
import UploadCSVForm from './UploadCSVForm';
import NewJudgeForm from './NewJudgeForm';

const AddJudgesPanel = () => {
return (
<div className="flex flex-col items-start justify-center w-full px-8 py-4 md:px-16 md:py-8">
<h1 className="text-4xl font-bold">Add Judges</h1>
<AddJudgeStatsPanel />
<div className="mt-8 flex flex-col w-full space-y-8">
<NewJudgeForm />
<UploadCSVForm />
</div>
</div>
);
};

export default AddJudgesPanel;
68 changes: 68 additions & 0 deletions client/src/components/admin/add-judges/NewJudgeForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useState } from 'react';

const NewJudgeForm = () => {
const [name, setName] = useState<string>('');
const [email, setEmail] = useState<string>('');
const [notes, setNotes] = useState<string>('');

const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

const AddJudge = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsSubmitting(true);
try {
await fetch(`${process.env.REACT_APP_JURY_URL}/judge/new`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email, notes }),
credentials: 'include',
});
} catch (err) {
console.log(err);
setIsSubmitting(false);
}

alert('Judge Added');
setName('');
setEmail('');
setNotes('');
setIsSubmitting(false);
};

return (
<>
<div className="w-full h-full border-lightest border-2 p-8 rounded-sm">
<div className="flex flex-col items-start h-full">
<h1 className="text-3xl">Add New Judges</h1>
<form className="flex flex-col w-full space-y-4" onSubmit={AddJudge}>
<div className="flex flex-row w-full mt-4 space-x-6">
<input
className="w-full h-14 px-4 text-2xl border-lightest border-2 rounded-sm focus:border-primary focus:border-4 focus:outline-none"
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<input
className="w-full h-14 px-4 text-2xl border-lightest border-2 rounded-sm focus:border-primary focus:border-4 focus:outline-none"
placeholder="Email Address"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<textarea
className="w-full h-36 px-4 py-4 text-2xl border-lightest border-2 rounded-sm focus:border-primary focus:border-4 focus:outline-none"
placeholder="Additional Notes"
value={notes}
onChange={(e) => setNotes(e.target.value)}
/>
<button className="w-full h-11 px-4 text-2xl text-white bg-primary rounded-full">
{isSubmitting ? 'Adding...' : 'Add'}
</button>
</form>
</div>
</div>
</>
);
};

export default NewJudgeForm;
147 changes: 147 additions & 0 deletions client/src/components/admin/add-judges/UploadCSVForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { useState } from 'react';

const UploadCSVForm = () => {
const [file, setFile] = useState<File | null>(null);
const [fileName, setFileName] = useState<string>('No file chosen');
const [headerRow, setHeaderRow] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);


const [isUploading, setIsUploading] = useState<boolean>(false);

const handleDrop: React.DragEventHandler<HTMLDivElement> = (e) => {
e.preventDefault();
if (e.dataTransfer.items) {
const file = e.dataTransfer.items[0].getAsFile();
if (file) {
setFile(file);
setFileName(file.name);
}
}
};

const UploadCSV = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsUploading(true);
setError(null);

try {
const formData = new FormData();
formData.append('csv', file as Blob);
formData.append('headerRow', headerRow.toString());
const response = await fetch(`${process.env.REACT_APP_JURY_URL}/judge/csv/upload`, {
method: 'POST',
body: formData,
credentials: 'include',
});

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

alert('CSV Uploaded');
setFile(null);
setFileName('No file chosen');
} catch (err) {
console.log(err);
setError(err as string);
} finally {
setIsUploading(false);
}
};


return (
<>
<div className="w-full h-full border-lightest border-2 p-8 rounded-sm">
<div className="flex flex-col items-start h-full">
<h1 className="text-3xl">Upload CSV</h1>
<p className="text-lg text-light">
CSV should be formatted in the order of name, email, and notes separated by
commas and then data on newlines
</p>
<form className="flex flex-col w-full space-y-4 mt-4" onSubmit={UploadCSV}>
<div
className="flex flex-col items-center justify-center w-full"
onDrop={handleDrop}
onDragOver={(e) => e.preventDefault()}
>
<label
htmlFor="dropzone-file"
className={`flex flex-col items-center justify-center w-full border-2 border-dashed rounded-sm cursor-pointer

${
error
? 'border-error bg-error/20'
: 'border-primary bg-primary/20'
}

`}
>
<div
className="flex flex-col items-center justify-center pt-5"
onDrop={handleDrop}
onDragOver={(e) => e.preventDefault()}
>
<p className="text-2xl text-center">
Drag & Drop files here to upload, <br />
or <span className="text-primary"> Browse Files</span>
</p>
</div>
<input
id="dropzone-file"
type="file"
className="hidden"
onChange={(e) => {
if (e.target.files) {
setFile(e.target.files[0]);
setFileName(e.target.files[0].name);
}
}}
/>
<div className="flex flex-row items-center justify-center pt-5 pb-6">
<input
type="checkbox"
checked={headerRow}
onChange={(e) => {
setHeaderRow(e.target.checked);
}}
className="mr-4 rounded-sm bg-white border-primary border-2 text-primary focus:ring-0"
/>
<p className="text-base text-center">
CSV contains a header row
</p>
</div>
</label>
</div>
{error && (
<div className="text-base text-center text-error">
Error Uploading CSV: {error}
</div>
)}
{file && (
<div className="flex w-full h-11 px-4 text-2xl border-2 border-lightest rounded-md text-start items-center">
File Chosen: {fileName}
</div>
)}
<div className="flex flex-row w-full mt-4 space-x-6">
<button
className={`w-full h-11 px-4 text-2xl text-white bg-primary rounded-full
${
isUploading || !file || !fileName
? 'opacity-50 cursor-not-allowed'
: ''
}`}
disabled={isUploading || !file || !fileName}
>
{isUploading ? 'Uploading...' : 'Upload'}
</button>
</div>
</form>
</div>
</div>
</>
);
};

export default UploadCSVForm;
4 changes: 2 additions & 2 deletions client/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import JudgeLogin from './judge/login';
import Judge from './judge';
import AdminLogin from './admin/login';
import Admin from './admin';
import AddProjects from './admin/add-projects';
import AddJudges from './admin/add-judges';
import AddProjects from './admin/AddProjects';
import AddJudges from './admin/AddJudges';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

Expand Down
2 changes: 1 addition & 1 deletion client/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ module.exports = {
},
},
},
plugins: [],
plugins: [require('@tailwindcss/forms')],
};
Loading