Skip to content

Commit 0fa6449

Browse files
committed
up
1 parent c523063 commit 0fa6449

31 files changed

+1133
-193
lines changed

.eslintrc.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2-
"extends": "next/core-web-vitals"
2+
"extends": "next/core-web-vitals",
3+
"rules": {
4+
"@next/next/no-img-element": 0
5+
}
36
}

README.md

+1-36
Original file line numberDiff line numberDiff line change
@@ -1,36 +1 @@
1-
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2-
3-
## Getting Started
4-
5-
First, run the development server:
6-
7-
```bash
8-
npm run dev
9-
# or
10-
yarn dev
11-
# or
12-
pnpm dev
13-
# or
14-
bun dev
15-
```
16-
17-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18-
19-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20-
21-
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
22-
23-
## Learn More
24-
25-
To learn more about Next.js, take a look at the following resources:
26-
27-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29-
30-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
31-
32-
## Deploy on Vercel
33-
34-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35-
36-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
1+
Code for FTMPC Event.
178 KB
Loading

public/Images/Developers/swapnil.jpg

1.83 MB
Loading
398 KB
Loading
587 KB
Loading

public/Images/links/behance.svg

+13
Loading

public/Images/links/dribble.svg

+12
Loading

public/Images/links/facebook.svg

+3
Loading

public/Images/links/github.svg

+3
Loading

public/Images/links/web.svg

+16
Loading

public/Images/modalbg.svg

+3
Loading
+254
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
import { db } from '@/config/firebase';
2+
import {
3+
addDoc,
4+
collection,
5+
deleteDoc,
6+
doc,
7+
getDocs,
8+
orderBy,
9+
query,
10+
serverTimestamp,
11+
updateDoc,
12+
} from 'firebase/firestore';
13+
import React, { FormEvent, useEffect, useState } from 'react';
14+
import { BsClock } from 'react-icons/bs';
15+
import { CgLock, CgSpinner } from 'react-icons/cg';
16+
import { GrAnnounce } from 'react-icons/gr';
17+
import Modal from '../Modal';
18+
import { LiaTimesSolid } from 'react-icons/lia';
19+
import { toast } from 'react-toastify';
20+
import { FaRegEdit } from 'react-icons/fa';
21+
import { FaPlus } from 'react-icons/fa6';
22+
import Field from '../Field';
23+
import Textarea from '../Textarea';
24+
import { TbTrash } from 'react-icons/tb';
25+
const Announcements = () => {
26+
const [announcements, setAnnouncements] = useState<any[]>([]);
27+
const [modalState, setModalState] = useState<boolean>(false);
28+
const [modalLoading, setModalLoading] = useState<boolean>(false);
29+
const [editState, setEditState] = useState<number | false>(false);
30+
const [title, setTitle] = useState<string>('');
31+
const [desc, setDesc] = useState<string>('');
32+
const [order, setOrder] = useState<number>(0);
33+
const closeModal = () => {
34+
setModalState(false);
35+
setEditState(false);
36+
setTitle('');
37+
setDesc('');
38+
setOrder(announcements[announcements.length - 1].order + 1 || 1580);
39+
};
40+
const loadAnnc = () => {
41+
getDocs(query(collection(db, 'announcements'), orderBy('order')))
42+
.then((docs) => {
43+
const annc: any[] = [];
44+
docs.forEach((data) => {
45+
annc.push({ id: data.id, ...data.data() });
46+
});
47+
annc.reverse();
48+
setAnnouncements(annc);
49+
})
50+
.catch((err) => {
51+
toast.error("Announcements can't be loaded");
52+
console.error(err);
53+
});
54+
};
55+
const addAnnc = (e: FormEvent) => {
56+
e.preventDefault();
57+
setModalLoading(true);
58+
addDoc(collection(db, 'announcements'), {
59+
title,
60+
description: desc,
61+
order,
62+
timestamp: serverTimestamp(),
63+
})
64+
.then(() => {
65+
toast.success('Success');
66+
loadAnnc();
67+
closeModal();
68+
setModalLoading(false);
69+
})
70+
.catch((err) => {
71+
toast.error("Announcements can't be added");
72+
console.error(err);
73+
setModalLoading(false);
74+
});
75+
};
76+
const deleteAnnc = (id: string) => {
77+
setModalLoading(true);
78+
deleteDoc(doc(db, 'announcements', id))
79+
.then(() => {
80+
toast.success('Success');
81+
loadAnnc();
82+
closeModal();
83+
setModalLoading(false);
84+
})
85+
.catch((err) => {
86+
toast.error("Announcements can't be edited");
87+
console.error(err);
88+
setModalLoading(false);
89+
});
90+
};
91+
const editAnnc = (e: FormEvent, id: string) => {
92+
e.preventDefault();
93+
94+
setModalLoading(true);
95+
updateDoc(doc(db, 'announcements', id), { title, description: desc, order })
96+
.then(() => {
97+
toast.success('Success');
98+
loadAnnc();
99+
closeModal();
100+
setModalLoading(false);
101+
})
102+
.catch((err) => {
103+
toast.error("Announcements can't be edited");
104+
console.error(err);
105+
setModalLoading(false);
106+
});
107+
};
108+
useEffect(() => {
109+
loadAnnc();
110+
}, []);
111+
useEffect(() => {
112+
if (announcements.length > 0) {
113+
setOrder(announcements[announcements.length - 1].order + 1 || 1580);
114+
}
115+
}, [announcements]);
116+
useEffect(() => {
117+
if (editState !== false) {
118+
setTitle(announcements[editState].title);
119+
setDesc(announcements[editState].description);
120+
setOrder(announcements[editState].order || 1580);
121+
setModalState(true);
122+
}
123+
}, [editState]);
124+
return (
125+
<div className="container p-6 md:p-8 pb-2 md:pb-4 bg-white rounded-xl my-8">
126+
<div className="flex flex-col md:flex-row gap-5 items-center justify-between">
127+
<div className="flex gap-5 items-center">
128+
<GrAnnounce className="w-12 h-12 text-primary" />
129+
<h1 className="text-4xl leading-none">
130+
<span className="">ANNOUNCEMENTS</span>
131+
</h1>
132+
</div>
133+
<div>
134+
<button
135+
type={'button'}
136+
onClick={() => {
137+
setModalState(true);
138+
}}
139+
className="hover:bg-primary_dark hover:text-white text-sm flex-1 justify-center transition-colors px-5 py-2 inline-flex focus:ring-2 focus:ring-secondary bg-primary text-white items-center gap-2 rounded-lg leading-[1.15] shadow-sm"
140+
>
141+
<FaPlus className="w-6 h-6" />
142+
Add Announcement
143+
</button>
144+
</div>
145+
</div>
146+
147+
<div className="flex flex-col gap-5 my-5 max-h-[550px] overflow-y-scroll overflow-x-clip">
148+
{announcements.map((data: any, index: number) => {
149+
return (
150+
<div className="p-5 bg-gray-100 rounded-xl" key={index}>
151+
<h3 className="text-xl Nunito font-bold">{data.title}</h3>
152+
<p className="min-h-[80px] md:min-h-0">{data.description}</p>
153+
<p className="justify-end text-sm flex gap-2 mt-4 mb-1 items-center text-zinc-500">
154+
<span className="mr-4">Order:{data.order}</span>
155+
<BsClock className="w-4 h-4 text-zinc-500" />
156+
{new Date(data.timestamp.seconds * 1000).toDateString()}
157+
</p>
158+
<div className="flex justify-end gap-5">
159+
<div className="flex-1" />
160+
<button
161+
className="text-primary text-right font-sm border-b-2 border-transparent hover:border-primary ml-auto mt-2 self-end l-2 flex gap-2 items-center"
162+
onClick={() => {
163+
setEditState(index);
164+
}}
165+
>
166+
<FaRegEdit className="w-4 h-4" />
167+
Edit
168+
</button>
169+
<button
170+
className="text-red-600 text-right font-sm border-b-2 border-transparent hover:border-red-600 ml-auto mt-2 self-end l-2 flex gap-2 items-center"
171+
onClick={() => {
172+
deleteAnnc(data.id);
173+
}}
174+
>
175+
<TbTrash className="w-4 h-4" />
176+
Delete
177+
</button>
178+
</div>
179+
</div>
180+
);
181+
})}
182+
</div>
183+
<Modal state={modalState}>
184+
{modalState ? (
185+
<div className="max-w-[95vw] w-[450px] rounded-xl bg-white p-6 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
186+
<div className="flex justify-end">
187+
<button
188+
className="text-primary text-right mb-5 font-medium border-b-2 border-transparent hover:border-primary ml-2 flex gap-2 items-center"
189+
onClick={closeModal}
190+
>
191+
<LiaTimesSolid className="w-4 h-4" />
192+
Close
193+
</button>
194+
</div>
195+
<h1 className="text-4xl mb-2">
196+
{editState !== false ? 'EDIT' : 'ADD'}{' '}
197+
<span className="text-primary">ANNOUNCEMENT</span>
198+
</h1>
199+
<form
200+
className="flex flex-col "
201+
onSubmit={
202+
editState !== false ? (e) => editAnnc(e, announcements[editState].id) : addAnnc
203+
}
204+
>
205+
<Field
206+
state={title}
207+
setValue={(name, data) => setTitle(String(data))}
208+
name="title"
209+
label="Title"
210+
type="text"
211+
/>{' '}
212+
<Field
213+
state={order}
214+
setValue={(name, data) => setOrder(Number(data))}
215+
name="Order"
216+
type="number"
217+
label="Order"
218+
/>{' '}
219+
<Textarea
220+
state={desc}
221+
setValue={(name, data) => setDesc(String(data))}
222+
name="Description"
223+
label="Description"
224+
/>{' '}
225+
<button
226+
type={'submit'}
227+
onClick={() => {
228+
setModalState(true);
229+
}}
230+
className="hover:bg-primary_dark mt-5 justify-self-end hover:text-white text-sm flex-1 justify-center transition-colors px-5 py-2 inline-flex focus:ring-2 focus:ring-secondary bg-primary text-white items-center gap-2 rounded-lg leading-[1.15] shadow-sm"
231+
>
232+
{modalLoading ? (
233+
<CgSpinner className="w-7 h-7 animate-spin text-secondary_light mx-auto" />
234+
) : editState !== false ? (
235+
<>
236+
<FaRegEdit className="w-6 h-6" />
237+
Edit
238+
</>
239+
) : (
240+
<>
241+
<FaPlus className="w-6 h-6" />
242+
Add
243+
</>
244+
)}
245+
</button>
246+
</form>
247+
</div>
248+
) : null}
249+
</Modal>
250+
</div>
251+
);
252+
};
253+
254+
export default Announcements;

0 commit comments

Comments
 (0)