Skip to content
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
37 changes: 4 additions & 33 deletions src/app/projects/page.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,12 @@
"use client";

import React, { useState } from "react";
import React from "react";
import ProjectsPage from "@/components/projects/ProjectsPage";

export default function Projects() {
const [isHovered, setIsHovered] = useState(false);

return (
<div className="flex min-h-screen items-center justify-center bg-[#080d14] font-Michroma text-white">
<div
className="group relative flex flex-col items-center gap-6 rounded-lg border border-white/10 bg-black/20 p-12 backdrop-blur-sm transition-all duration-500 hover:border-white/20 hover:shadow-lg hover:shadow-white/5"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{/* Main text */}
<h1 className="text-center font-Michroma text-4xl font-bold tracking-wider">
COMING
</h1>
<h1 className="text-center font-Michroma text-5xl font-bold tracking-wider text-blue-400">
SOON!
</h1>

{/* Animated underline */}
<div className="relative mt-2">
<div
className={`h-0.5 bg-gradient-to-r from-transparent via-blue-400 to-transparent transition-all duration-500 ${
isHovered ? "w-48" : "w-32"
}`}
/>
</div>

{/* Subtitle */}
<p className="mt-4 text-center text-sm text-gray-400">
We're building something awesome.
<br />
Stay tuned!
</p>
</div>
<div>
<ProjectsPage />
</div>
);
}
94 changes: 79 additions & 15 deletions src/components/admin/projects/AddForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use client";

import React, { useState } from "react";
import { addDoc, collection } from "firebase/firestore";
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
import { db, storage } from "@/lib/firebase/firebase";
import { ProjectFormData, Parts, Project } from "@/types/project";
import { ProjectFormData, Parts } from "@/types/project";

interface AddFormProps {
initialData?: ProjectFormData;
Expand All @@ -27,6 +29,10 @@ const emptyFormState: ProjectFormData = {
Photos: "",
Image: "",
Builders: [""],
semester: {
term: "Fall",
year: new Date().getFullYear(),
},
};

export default function AddForm({
Expand All @@ -40,31 +46,40 @@ export default function AddForm({
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);

const [selectedImage, setSelectedImage] = useState<File | null>(null);
const [imagePreview, setImagePreview] = useState<string>(
formData.Image || "",
);
const [uploadProgress, setUploadProgress] = useState<number>(0);

const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
e: React.ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>,
) => {
const { name, value } = e.target;
if (name.includes(".")) {
// Handle nested Parts object
// Handle nested objects (Parts and semester)
const [parent, child] = name.split(".");
if (parent === "Parts") {
setFormData((prev: ProjectFormData) => ({
setFormData((prev) => ({
...prev,
Parts: {
...prev.Parts,
[child]: value,
},
}));
} else if (parent === "semester") {
setFormData((prev) => ({
...prev,
semester: {
...prev.semester,
[child]: child === "year" ? Number(value) : value,
},
}));
}
} else {
setFormData((prev: ProjectFormData) => ({
setFormData((prev) => ({
...prev,
[name]: value,
}));
Expand Down Expand Up @@ -103,33 +118,39 @@ export default function AddForm({
try {
let imageUrl = formData.Image;

// Upload new image if selected
if (selectedImage) {
imageUrl = await uploadImage(selectedImage);
}

// Filter out empty builders
const cleanedData = {
// Clean the data
const cleanedData: ProjectFormData = {
...formData,
Image: imageUrl,
Builders: formData.Builders.filter((builder) => builder.trim() !== ""),
};

if (onSubmit) {
// If onSubmit prop exists (editing mode), use it
await onSubmit(cleanedData);
} else {
// Direct submission to Firebase
console.log("Submitting to Firebase:", cleanedData); // Debug log
const docRef = await addDoc(collection(db, "Projects"), cleanedData);
console.log("Document written with ID: ", docRef.id);
}

setSuccess(true);

// Only reset form if not editing
if (!isEditing) {
setFormData(emptyFormState);
setSelectedImage(null);
setImagePreview("");
}
} catch (e) {
console.error("Error in submission:", e); // Debug log
setError(e instanceof Error ? e.message : "An error occurred");
console.error("Error adding document: ", e);
} finally {
setIsSubmitting(false);
}
Expand Down Expand Up @@ -174,11 +195,11 @@ export default function AddForm({
};

return (
<div className="mx-auto max-w-4xl sm:p-6 py-5 px-4">
<div className="mx-auto max-w-4xl px-4 py-5 sm:p-6">
<form onSubmit={handleSubmit} className="space-y-6">
{/* Basic Information */}
<div className="space-y-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<label htmlFor="Title" className="block text-sm font-medium">
Title
Expand All @@ -194,6 +215,50 @@ export default function AddForm({
/>
</div>

{/* Add Semester Selection */}
<div className="flex gap-4">
<div className="flex-1">
<label
htmlFor="semesterTerm"
className="block text-sm font-medium"
>
Term
</label>
<select
id="semesterTerm"
name="semester.term"
value={formData.semester.term}
onChange={handleChange}
className="mt-1 w-full rounded-md border bg-white p-2 text-gray-900"
required
>
<option value="Spring">Spring</option>
<option value="Summer">Summer</option>
<option value="Fall">Fall</option>
</select>
</div>

<div className="flex-1">
<label
htmlFor="semesterYear"
className="block text-sm font-medium"
>
Year
</label>
<input
type="number"
id="semesterYear"
name="semester.year"
value={formData.semester.year}
onChange={handleChange}
min="2000"
max="2099"
className="mt-1 w-full rounded-md border bg-white p-2 text-gray-900"
required
/>
</div>
</div>

<div>
<label
htmlFor="Description"
Expand Down Expand Up @@ -260,7 +325,7 @@ export default function AddForm({
<img
src={imagePreview}
alt="Preview"
className="max-w-[320px] w-full rounded"
className="w-full max-w-[320px] rounded"
/>
</div>
)}
Expand Down Expand Up @@ -329,7 +394,7 @@ export default function AddForm({
<button
type="button"
onClick={addBuilder}
className="rounded-md bg-green-500 px-4 py-2 text-white text-sm sm:text-base"
className="rounded-md bg-green-500 px-4 py-2 text-sm text-white sm:text-base"
>
Add Builder
</button>
Expand All @@ -339,7 +404,7 @@ export default function AddForm({
<button
type="submit"
disabled={isSubmitting}
className="w-full rounded-md bg-blue-500 p-3 text-white disabled:bg-blue-300 text-sm sm:text-base"
className="w-full rounded-md bg-blue-500 p-3 text-sm text-white disabled:bg-blue-300 sm:text-base"
>
{isSubmitting
? "Submitting..."
Expand All @@ -349,7 +414,6 @@ export default function AddForm({
</button>

{error && <div className="mt-2 text-red-500">{error}</div>}

{success && (
<div className="mt-2 text-green-500">
{isEditing
Expand Down
40 changes: 22 additions & 18 deletions src/components/admin/projects/EditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,17 @@ export default function EditForm() {
try {
const projectRef = doc(db, "Projects", selectedProject.id);

// Convert ProjectFormData to a plain object that Firestore can handle
const firestoreData = {
Youtube: updatedData.Youtube,
Description: updatedData.Description,
Title: updatedData.Title,
Photos: updatedData.Photos,
Image: updatedData.Image,
Builders: updatedData.Builders,
semester: {
term: updatedData.semester.term,
year: updatedData.semester.year,
},
Parts: {
RAM: updatedData.Parts.RAM,
Cooling: updatedData.Parts.Cooling,
Expand All @@ -88,16 +91,13 @@ export default function EditForm() {

// Update local state
setProjects((prevProjects) =>
prevProjects.map((project) =>
project.id === selectedProject.id
? { ...project, ...updatedData }
: project,
prevProjects.map((proj) =>
proj.id === selectedProject.id ? { ...proj, ...updatedData } : proj,
),
);

setIsModalOpen(false);
setSelectedProject(null);
//alert('Project updated successfully');
} catch (err) {
console.error("Error updating project:", err);
setError("Failed to update project");
Expand Down Expand Up @@ -163,35 +163,39 @@ export default function EditForm() {
</div>

{/* Projects List */}
<div className="space-y-4">
{projects
.filter((project) =>
project.Title.toLowerCase().includes(searchQuery.toLowerCase()),
)
.map((project) => (
{projects
.filter(
(
proj, // Changed from project to proj
) => proj.Title.toLowerCase().includes(searchQuery.toLowerCase()),
)
.map(
(
proj, // Changed from project to proj
) => (
<div
key={project.id}
key={proj.id} // Changed from project to proj
className="flex items-center justify-between rounded border p-4 text-sm sm:text-base"
>
<h3 className="font-bold">{project.Title}</h3>
<h3 className="font-bold">{proj.Title}</h3>
<div className="flex gap-2">
<button
onClick={() => handleEditClick(project)}
onClick={() => handleEditClick(proj)} // Changed from project to proj
className="rounded bg-blue-500 px-4 py-2 text-white transition-colors hover:bg-blue-600"
>
Edit
</button>
<button
onClick={() => handleDeleteClick(project)}
onClick={() => handleDeleteClick(proj)} // Changed from project to proj
className="flex items-center gap-2 rounded bg-red-500 px-4 py-2 text-white transition-colors hover:bg-red-600"
>
<Trash2 size={18} />
Delete
</button>
</div>
</div>
))}
</div>
),
)}

{/* Edit Modal */}
{isModalOpen && selectedProject && (
Expand Down
Loading
Loading