feat(hackathon): Improve dark mode and UI/UX in Hackathon website (#64)
* feat: update landing page * feat: Add favicon and SEO (JSON-LD schema, meta tags) - Add favicon image - Add JSON-LD schema for Hackathon event - Add react-helmet-async for managing meta tags * chore: remove react-helmet-async * chore: update landing page * chore: update UI for signup and login - add back button for better UX * feat: add image loading state and skeleton UI for team dashboard * fix: landing navbar not sticky to top, fix onboarding UI * feat(hackathon): update UI - Update dashboard, onboarding user, edit profile, and team layout to make it more consistent * fix: optimize placeholder banner image & minor fix dark mode * feat(hackathon): update landing page dark mode color scheme * feat(hackathon): update auth page dark mode color scheme * feat(hackathon): dashboard UI improvement and dark mode adjustment * feat(hackathon): browse team page - update dark mode color scheme - add some border style to give outline and depth - change emoji to icon * feat(hackathon): update team page - update dark mode color scheme for team page: view, team edit, and submit project page - fix bug in chat where messages are displayed double - make the form field size consistent * feat(hackathon): update dark mode onboarding and edit profile --------- Co-authored-by: Maulana Sodiqin <sodiqincahyana1@gmail.com> Co-authored-by: Muhammad Zakir Ramadhan <61570975+zakirkun@users.noreply.github.com>
This commit is contained in:
co-authored by
Maulana Sodiqin
Muhammad Zakir Ramadhan
parent
66b8b064ba
commit
bc5b072ad8
@@ -23,7 +23,8 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
|
||||
const { data: teamData } = useTeamById(teamId || '');
|
||||
const { data: submissionData } = useTeamSubmission(teamId || '', !!teamId);
|
||||
const { mutateAsync: submitProject, isPending: isSubmitting } = useSubmitProject(teamId || '');
|
||||
const { mutateAsync: submitProject, isPending: isSubmitting } =
|
||||
useSubmitProject(teamId || '');
|
||||
const { mutateAsync: uploadFile, isPending: isUploading } = useUploadFile();
|
||||
|
||||
const team = teamData?.data;
|
||||
@@ -38,25 +39,38 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
|
||||
if (!isLeader) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 dark:bg-neutral-950">
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">Access Denied</h2>
|
||||
<p className="text-gray-600 dark:text-neutral-400 mb-4">Only the team leader can submit projects</p>
|
||||
<Button onClick={() => navigate(`/teams/${teamId}`)}>Back to Team</Button>
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 dark:bg-gray-950">
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Access Denied
|
||||
</h2>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-4">
|
||||
Only the team leader can submit projects
|
||||
</p>
|
||||
<Button onClick={() => navigate(`/teams/${teamId}`)}>
|
||||
Back to Team
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasSubmission) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 dark:bg-neutral-950">
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 dark:bg-gray-950">
|
||||
<div className="text-6xl mb-4">✅</div>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">Project Already Submitted</h2>
|
||||
<p className="text-gray-600 dark:text-neutral-400 mb-4">Your team has already submitted a project</p>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Project Already Submitted
|
||||
</h2>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-4">
|
||||
Your team has already submitted a project
|
||||
</p>
|
||||
<div className="flex space-x-3">
|
||||
<Button onClick={() => navigate(`/teams/${teamId}/submission`)}>
|
||||
View Submission
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={() => navigate(`/teams/${teamId}`)}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => navigate(`/teams/${teamId}`)}
|
||||
>
|
||||
Back to Team
|
||||
</Button>
|
||||
</div>
|
||||
@@ -64,14 +78,16 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
);
|
||||
}
|
||||
|
||||
const handleScreenshotUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handleScreenshotUpload = async (
|
||||
e: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
|
||||
try {
|
||||
const uploadPromises = Array.from(files).map(file => uploadFile(file));
|
||||
const uploadPromises = Array.from(files).map((file) => uploadFile(file));
|
||||
const results = await Promise.all(uploadPromises);
|
||||
const urls = results.map(r => r.data.url);
|
||||
const urls = results.map((r) => r.data.url);
|
||||
setScreenshots([...screenshots, ...urls]);
|
||||
} catch (error) {
|
||||
console.error('Failed to upload screenshots:', error);
|
||||
@@ -95,11 +111,13 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-neutral-950">
|
||||
<div className="bg-white dark:bg-neutral-900 border-b dark:border-neutral-700">
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-950">
|
||||
<div className="bg-white dark:bg-gray-900 border-b dark:border-gray-700">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">Submit Project</h1>
|
||||
<p className="text-gray-600 dark:text-neutral-400 mt-1">{team?.name}</p>
|
||||
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
|
||||
Submit Project
|
||||
</h1>
|
||||
<p className="text-gray-600 dark:text-gray-400 mt-1">{team?.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,33 +127,42 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
<div className="flex items-start space-x-3">
|
||||
<span className="text-3xl">⚠️</span>
|
||||
<div>
|
||||
<h3 className="font-bold text-red-900 dark:text-red-100 text-lg">IMPORTANT WARNING</h3>
|
||||
<ul className="text-red-800 dark:text-red-200 mt-2 space-y-1 text-sm">
|
||||
<h3 className="font-bold text-red-900 dark:text-red-100 text-lg">
|
||||
IMPORTANT WARNING
|
||||
</h3>
|
||||
<ul className="text-red-800 dark:text-red-200 mt-2 space-y-1 text-sm font-sans">
|
||||
<li>• You can only submit your project ONCE</li>
|
||||
<li>• After submission, you CANNOT edit or change anything</li>
|
||||
<li>• Make sure all information is correct before submitting</li>
|
||||
<li>
|
||||
• Make sure all information is correct before submitting
|
||||
</li>
|
||||
<li>• Review your project details carefully</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white dark:bg-neutral-900 rounded-lg shadow-md dark:shadow-neutral-950/50 p-8">
|
||||
<form onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
setShowConfirmModal(true);
|
||||
}} className="space-y-6">
|
||||
<div className="bg-white dark:bg-gray-900 rounded-lg shadow-md dark:shadow-gray-950/50 p-8 border dark:border-gray-800">
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
setShowConfirmModal(true);
|
||||
}}
|
||||
className="space-y-6"
|
||||
>
|
||||
{/* Project Name */}
|
||||
<ControlledInputField
|
||||
control={form.control}
|
||||
label="Project Name"
|
||||
placeholder="Enter your project name"
|
||||
name="project_name"
|
||||
size="lg"
|
||||
isRequired={true}
|
||||
/>
|
||||
|
||||
{/* Description */}
|
||||
<div className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-neutral-300">
|
||||
<label className="block text-[15px] font-medium text-gray-700 dark:text-gray-300">
|
||||
Project Description <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<Controller
|
||||
@@ -148,9 +175,12 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
placeholder="Describe your project, its features, and what problem it solves..."
|
||||
rows={6}
|
||||
className="w-full"
|
||||
size="lg"
|
||||
/>
|
||||
{fieldState.error && (
|
||||
<p className="text-sm text-red-500 mt-1">{fieldState.error.message}</p>
|
||||
<p className="text-sm text-red-500 mt-1">
|
||||
{fieldState.error.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -164,6 +194,8 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
placeholder="https://github.com/username/project"
|
||||
name="repository_url"
|
||||
type="url"
|
||||
size="lg"
|
||||
isRequired={true}
|
||||
/>
|
||||
|
||||
{/* Demo URL */}
|
||||
@@ -173,6 +205,7 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
placeholder="https://your-project-demo.com"
|
||||
name="demo_url"
|
||||
type="url"
|
||||
size="lg"
|
||||
/>
|
||||
|
||||
{/* Presentation URL */}
|
||||
@@ -182,12 +215,13 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
placeholder="https://slides.com/your-presentation or Google Drive link"
|
||||
name="presentation_url"
|
||||
type="url"
|
||||
size="lg"
|
||||
/>
|
||||
|
||||
{/* Screenshots */}
|
||||
<div className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-neutral-300">
|
||||
Project Screenshots <span className="text-gray-400 dark:text-neutral-500">(Optional)</span>
|
||||
<div>
|
||||
<label className="block text-label1 font-medium text-neutral-800 dark:text-gray-300">
|
||||
Project Screenshots (Optional)
|
||||
</label>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 mb-4">
|
||||
{screenshots.map((url, index) => (
|
||||
@@ -195,7 +229,7 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
<img
|
||||
src={url}
|
||||
alt={`Screenshot ${index + 1}`}
|
||||
className="w-full h-32 object-cover rounded-lg border-2 border-gray-200 dark:border-neutral-700"
|
||||
className="w-full h-32 object-cover rounded-lg border-2 border-gray-200 dark:border-gray-700"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -207,10 +241,14 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<label className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed border-gray-300 dark:border-neutral-600 rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-neutral-800">
|
||||
<label className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800">
|
||||
<div className="text-center">
|
||||
<p className="text-gray-500 dark:text-neutral-400">Click to upload screenshots</p>
|
||||
<p className="text-xs text-gray-400 dark:text-neutral-500 mt-1">PNG, JPG up to 5MB each</p>
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
Click to upload screenshots
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1 font-sans">
|
||||
PNG, JPG up to 5MB each
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
type="file"
|
||||
@@ -248,7 +286,7 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
{/* Confirmation Modal */}
|
||||
{showConfirmModal && (
|
||||
<div className="fixed inset-0 bg-black/50 dark:bg-black/70 flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white dark:bg-neutral-900 rounded-lg shadow-xl dark:shadow-neutral-950/50 max-w-md w-full p-6">
|
||||
<div className="bg-white dark:bg-gray-900 rounded-lg shadow-xl dark:shadow-gray-950/50 max-w-md w-full p-6">
|
||||
<div className="text-center mb-6">
|
||||
<div className="text-5xl mb-4">⚠️</div>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
@@ -258,11 +296,11 @@ const SubmitProjectPage: FC = (): ReactElement => {
|
||||
This action is IRREVERSIBLE!
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-gray-50 dark:bg-neutral-800 rounded-lg p-4 mb-6">
|
||||
<p className="text-sm text-gray-700 dark:text-neutral-300 mb-3">
|
||||
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-4 mb-6">
|
||||
<p className="text-sm text-gray-700 dark:text-gray-300 mb-3">
|
||||
By clicking "Submit Project", you confirm that:
|
||||
</p>
|
||||
<ul className="text-sm text-gray-600 dark:text-neutral-400 space-y-2">
|
||||
<ul className="text-sm text-gray-600 dark:text-gray-400 space-y-2">
|
||||
<li>✓ All information is correct and complete</li>
|
||||
<li>✓ You understand this can only be done once</li>
|
||||
<li>✓ You cannot edit after submission</li>
|
||||
|
||||
Reference in New Issue
Block a user