Skip to content

Commit 1c500a0

Browse files
Added "admin/projects" (#50)
* Added admin/projects * secured by adding env * fixed an error * fixed commented errors * small fixes --------- Co-authored-by: AbhijeetMankani <abhijeetmankani@gmail.com>
1 parent 87c80e7 commit 1c500a0

File tree

11 files changed

+562
-34
lines changed

11 files changed

+562
-34
lines changed

.env.sample

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
FIREBASE_API_KEY=
22
FIREBASE_AUTH_DOMAIN=
3+
FIREBASE_DATABASE_URL=
34
FIREBASE_PROJECT_ID=
45
FIREBASE_STORAGE_BUCKET=
56
FIREBASE_MESSAGING_SENDER_ID=
67
FIREBASE_APP_ID=
7-
FIREBASE_MEASUREMENT_ID=
8+
FIREBASE_MEASUREMENT_ID=
9+
10+
CLOUDINARY_CLOUD_NAME=
11+
CLOUDINARY_UPLOAD_PRESET=

lib/GetProjects.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use client';
2+
//import React, { useState, useEffect } from 'react';
3+
import { collection, getDocs } from 'firebase/firestore';
4+
import { db } from '../src/firebase';
5+
6+
export default async function GetProjects() {
7+
try {
8+
// Reference to 'users' collection
9+
const querySnapshot = await getDocs(collection(db, 'projects'));
10+
11+
// Map the documents from the snapshot to an array of user data
12+
const projectsData = querySnapshot.docs.map((doc) => ({
13+
id: doc.id,
14+
...doc.data(),
15+
}));
16+
return projectsData;
17+
} catch (error) {
18+
console.error('Error reading data: ', error);
19+
}
20+
}

next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ const nextConfig = {
44
env: {
55
FIREBASE_API_KEY: process.env.FIREBASE_API_KEY,
66
FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN,
7+
FIREBASE_DATABASE_URL: process.env.FIREBASE_DATABASE_URL,
78
FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
89
FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET,
910
FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID,
1011
FIREBASE_APP_ID: process.env.FIREBASE_APP_ID,
1112
FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID,
13+
14+
CLOUDINARY_CLOUD_NAME: process.env.CLOUDINARY_CLOUD_NAME,
15+
CLOUDINARY_UPLOAD_PRESET: process.env.CLOUDINARY_UPLOAD_PRESET,
1216
},
1317
};
1418

package-lock.json

Lines changed: 302 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
"@mui/material": "^5.13.0",
2121
"@mui/system": "^5.13.7",
2222
"@next/font": "13.1.6",
23+
"@popperjs/core": "^2.11.8",
2324
"@react-aria/i18n": "^3.12.4",
2425
"@types/gsap": "^3.0.0",
2526
"@types/node": "18.11.19",
2627
"@types/react": "18.0.27",
2728
"@types/react-dom": "18.0.10",
29+
"axios": "^1.7.9",
30+
"bootstrap": "^5.3.3",
2831
"dotenv": "^16.4.6",
2932
"firebase": "^10.14.1",
3033
"firebase-admin": "^12.6.0",
@@ -34,6 +37,7 @@
3437
"gsap": "^3.12.2",
3538
"lint-staged": "^15.2.0",
3639
"markdown-to-jsx": "^7.3.2",
40+
"multer": "^1.4.5-lts.1",
3741
"next": "^14.2.15",
3842
"react": "18.2.0",
3943
"react-dom": "18.2.0",

src/components/Projects/projects.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
1+
import React, { useState, useEffect } from 'react';
12
import Card from '@/components/Projects/ProjectCard';
23
import { bgColor, color, h4, h5 } from '@/constants';
34
import { Box, Typography, useMediaQuery } from '@mui/material';
4-
import modelData from '@/data/projects';
5+
import GetProjects from 'lib/GetProjects';
56

67
export default function Projects() {
78
const breakPoint = useMediaQuery('(min-width:600px)');
89
const breakPoint2 = useMediaQuery('(min-width:750px)');
10+
const [projectsData, setProjectsData] = useState([]);
11+
12+
useEffect(() => {
13+
try {
14+
const fetchData = async () => {
15+
const project = await GetProjects();
16+
setProjectsData(project);
17+
console.log(GetProjects());
18+
};
19+
fetchData();
20+
} catch (error) {
21+
console.error('Error reading data: ', error);
22+
}
23+
}, []);
924

1025
return (
1126
<>
@@ -36,12 +51,12 @@ export default function Projects() {
3651
}
3752
justifyContent={breakPoint ? 'space-between' : 'center'}
3853
>
39-
{modelData.map((modelDataInst, index) => (
54+
{projectsData.map((model, id) => (
4055
<Card
41-
key={index}
42-
projectName={modelDataInst.modelName}
43-
projectContent={modelDataInst.modelDesc}
44-
projectThumbnail={modelDataInst.modelImg}
56+
key={id}
57+
projectName={model.modelName}
58+
projectContent={model.modelDesc}
59+
projectThumbnail={model.modelImg}
4560
/>
4661
))}
4762
</Box>

src/firebase.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Import the functions you need from the SDKs you need
22
import { initializeApp } from 'firebase/app';
33
import { getFirestore } from 'firebase/firestore';
4+
//import { getStorage } from 'firebase/storage';
45

56
// TODO: Add SDKs for Firebase products that you want to use
67
// https://firebase.google.com/docs/web/setup#available-libraries
@@ -10,6 +11,7 @@ import { getFirestore } from 'firebase/firestore';
1011
const firebaseConfig = {
1112
apiKey: process.env.FIREBASE_API_KEY,
1213
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
14+
databaseURL: process.env.FIREBASE_DATABASE_URL,
1315
projectId: process.env.FIREBASE_PROJECT_ID,
1416
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
1517
messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
@@ -20,3 +22,4 @@ const firebaseConfig = {
2022
// Initialize Firebase
2123
const app = initializeApp(firebaseConfig);
2224
export const db = getFirestore(app);
25+
//export const storage = getStorage(app);

src/pages/admin/blogs/index.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import styles from '../../../styles/Markdown.module.css';
44
import { db } from '../../../firebase.js';
55
import { bgColor, color, h4, h5, h5_, h6, h6_ } from '@/constants';
66
import { Box, Typography, useMediaQuery } from '@mui/material';
7-
import { today, getLocalTimeZone } from "@internationalized/date";
7+
import { today, getLocalTimeZone } from '@internationalized/date';
88
import Markdown from 'markdown-to-jsx';
99

1010
// Define the function type for addUser
@@ -16,11 +16,11 @@ export default function BlogEdit() {
1616

1717
const [title, setTitle] = useState('');
1818
const [subtitle, setSubtitle] = useState('');
19-
const [date, setDate] = useState(now.day + "-" + now.month + "-" + now.year);
19+
const [date, setDate] = useState(
20+
now.day + '-' + now.month + '-' + now.year
21+
);
2022
const [content, setContent] = useState('');
2123

22-
23-
2424
const [isPrevClicked, setIsPrevClicked] = useState<boolean>(false);
2525
const [isEditClicked, setIsEditClicked] = useState<boolean>(true);
2626

@@ -34,7 +34,6 @@ export default function BlogEdit() {
3434
setIsPrevClicked(false);
3535
};
3636

37-
3837
const handleSubmit = async () => {
3938
try {
4039
// Add a new document to the 'users' collection
@@ -163,14 +162,19 @@ export default function BlogEdit() {
163162
className={styles.previewTab}
164163
style={{ display: isEditClicked ? 'none' : 'block' }}
165164
>
166-
167165
<Typography
168166
variant="h2"
169167
color={color}
170-
fontSize={breakPoint ? h5 : h5_}>
168+
fontSize={breakPoint ? h5 : h5_}
169+
>
171170
Blog Listing Preview
172171
</Typography>
173-
<Box mb="35px" padding="10px 7.5% 100px" bgcolor={bgColor} color="white">
172+
<Box
173+
mb="35px"
174+
padding="10px 7.5% 100px"
175+
bgcolor={bgColor}
176+
color="white"
177+
>
174178
<Typography
175179
variant="h2"
176180
color={color}
@@ -203,11 +207,16 @@ export default function BlogEdit() {
203207
<Typography
204208
variant="h2"
205209
color={color}
206-
fontSize={breakPoint ? h5 : h5_}>
210+
fontSize={breakPoint ? h5 : h5_}
211+
>
207212
Blog Content preview
208213
</Typography>
209214

210-
<Box padding="10px 7.5% 100px" bgcolor={bgColor} color="white">
215+
<Box
216+
padding="10px 7.5% 100px"
217+
bgcolor={bgColor}
218+
color="white"
219+
>
211220
<Typography
212221
variant="h1"
213222
color={color}
@@ -239,9 +248,6 @@ export default function BlogEdit() {
239248
</Typography>
240249
</Box>
241250
</Box>
242-
243-
244-
245251
</div>
246252
</div>
247253
</div>

src/pages/admin/projects/index.tsx

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import React, { useState } from 'react';
2+
import { collection, addDoc } from 'firebase/firestore';
3+
import { db } from '../../../firebase.js';
4+
import { bgColor, color, h4, h5, h5_, h6, h6_ } from '@/constants';
5+
import axios from 'axios';
6+
import { border, borderRadius } from '@mui/system';
7+
import styles from "@/styles/admin.projects.module.css"
8+
9+
export default function AddProject() {
10+
const [modelName, setModelName] = useState('');
11+
const [file, setFile] = useState(null);
12+
const [modelDesc, setModelDesc] = useState('');
13+
14+
const handleSubmit = async () => {
15+
if (!file) {
16+
alert('Please select a file first!');
17+
return;
18+
}
19+
20+
const formData = new FormData();
21+
formData.append('file', file);
22+
formData.append('upload_preset', 'model_image'); // Replace with your Cloudinary upload preset
23+
formData.append('cloud_name', 'dxxurstw7');
24+
25+
try {
26+
const response = await axios.post(
27+
'https://api.cloudinary.com/v1_1/dxxurstw7/image/upload', // Replace with your Cloudinary endpoint
28+
formData
29+
);
30+
// Add a new document to the 'users' collection
31+
await addDoc(collection(db, 'projects'), {
32+
modelName: modelName,
33+
modelImg: response.data.secure_url,
34+
modelDesc: modelDesc,
35+
});
36+
console.log('Document written successfully');
37+
} catch {
38+
console.log('Error adding document');
39+
}
40+
setModelName('');
41+
setFile(null);
42+
setModelDesc('');
43+
};
44+
45+
return (
46+
<div
47+
style={{
48+
backgroundColor: bgColor,
49+
color: color,
50+
display: 'flex',
51+
flexDirection: 'column',
52+
alignItems: 'center',
53+
}}
54+
>
55+
<h1
56+
style={{
57+
display: 'block',
58+
fontSize: h4,
59+
marginBottom: '50px',
60+
}}
61+
>
62+
Add Projects
63+
</h1>
64+
<div
65+
style={{
66+
width: '80%',
67+
marginBottom: '50px',
68+
}}
69+
>
70+
<label style={{ fontSize: h5_ }} htmlFor="modelName">
71+
Project Name :
72+
</label>
73+
<input
74+
name="modelName"
75+
placeholder="Enter project name"
76+
type="text"
77+
onChange={(e) => setModelName(e.target.value)}
78+
value={modelName}
79+
style={{
80+
backgroundColor: color,
81+
width: '100%',
82+
fontSize: h6,
83+
height: '40px',
84+
borderRadius: '1rem',
85+
marginTop: '20px',
86+
padding: '10px',
87+
}}
88+
/>
89+
</div>
90+
<div
91+
style={{
92+
width: '80%',
93+
marginBottom: '50px',
94+
}}
95+
>
96+
<label style={{ fontSize: h5_ }} htmlFor="modelImg">
97+
Project Image :
98+
</label>
99+
<br />
100+
<div className={styles.fileInputWrapper}>
101+
<button className={styles.fileInputButton}
102+
style={{
103+
fontSize: h6,
104+
borderRadius: '1rem',
105+
marginTop: '20px',
106+
marginRight: '10px',
107+
}}>Choose File</button>
108+
<input
109+
name="modelImg"
110+
type="file"
111+
accept="image/*"
112+
onChange={(e) => setFile(e.target.files[0])}
113+
className={styles.fileInput}
114+
style={{
115+
fontSize: h6,
116+
borderRadius: '1rem',
117+
marginTop: '20px',
118+
}}
119+
/>
120+
</div>
121+
</div>
122+
<div
123+
style={{
124+
width: '80%',
125+
marginBottom: '60px',
126+
}}
127+
>
128+
<label style={{ fontSize: h5_ }} htmlFor="modelDesc">
129+
Project Description :
130+
</label>
131+
<textarea
132+
name="modelDesc"
133+
placeholder="Enter project description"
134+
onChange={(e) => setModelDesc(e.target.value)}
135+
style={{
136+
backgroundColor: color,
137+
width: '100%',
138+
fontSize: h6,
139+
height: '100px',
140+
borderRadius: '1rem',
141+
marginTop: '20px',
142+
padding: '10px',
143+
}}
144+
value={modelDesc}
145+
></textarea>
146+
</div>
147+
<button
148+
style={{
149+
marginBottom: '30px',
150+
width: '8rem',
151+
height: '4rem',
152+
backgroundColor: '#50C878',
153+
borderRadius: '1rem',
154+
fontSize: h6_,
155+
}}
156+
id="add"
157+
onClick={() => handleSubmit()}
158+
value={modelDesc}
159+
>
160+
Add
161+
</button>
162+
</div>
163+
);
164+
}

src/pages/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import MovingText from '@/components/MovingText';
88
import { bgColor, color, h4, h5, h6, titleColor } from '@/constants';
99
import Projects from '../components/Projects/projects';
1010
import Image from 'next/image';
11+
1112
export default function Home() {
1213
const breakPoint = useMediaQuery('(min-width:600px)');
1314
const breakPoint2 = useMediaQuery('(min-width:1000px)');

0 commit comments

Comments
 (0)