Skip to content

Commit 67f3166

Browse files
authored
Merge pull request #40 from shamil-tp/sinan
cleaned version of code
2 parents 196d91b + c5c039e commit 67f3166

12 files changed

Lines changed: 22 additions & 79 deletions

File tree

frontend/src/api/axios.jsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import secureLocalStorage from "react-secure-storage";
44
const api = axios.create({
55
baseURL: import.meta.env.VITE_BACKEND_URL,
66
withCredentials:true
7-
}); // credentials not needed for Bearer token auth
7+
});
88

99
// Request Interceptor: Attach Access Token
1010
api.interceptors.request.use(
@@ -36,10 +36,8 @@ api.interceptors.response.use(
3636
const refreshToken = secureLocalStorage.getItem("refreshToken");
3737
if (!refreshToken) {
3838
console.log("Axios Interceptor: No Refresh Token found. Logging out.");
39-
// No refresh token, logout user
4039
secureLocalStorage.removeItem("accessToken");
4140
secureLocalStorage.removeItem("refreshToken");
42-
// window.location.href = "/login"; // Optional: Redirect to login
4341
return Promise.reject(error);
4442
}
4543

@@ -51,16 +49,13 @@ api.interceptors.response.use(
5149
console.log("Axios Interceptor: Refresh Successful. New Access Token received.");
5250
const { accessToken } = res.data;
5351
secureLocalStorage.setItem("accessToken", accessToken);
54-
// If rotating refresh token: secureLocalStorage.setItem("refreshToken", res.data.refreshToken);
5552

56-
// Update header and retry original request
5753
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
5854
return api(originalRequest);
5955
} catch (refreshError) {
6056
console.error("Token refresh failed:", refreshError);
6157
secureLocalStorage.removeItem("accessToken");
6258
secureLocalStorage.removeItem("refreshToken");
63-
// window.location.href = "/login"; // Optional: Redirect to login
6459
return Promise.reject(refreshError);
6560
}
6661
}

frontend/src/components/BlogRenderer.jsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
import React from 'react';
2-
import 'react-quill-new/dist/quill.snow.css'; // Import styles for consistent text formatting
2+
import 'react-quill-new/dist/quill.snow.css';
33

44
const BlogRenderer = ({ content }) => {
55
if (!content || !Array.isArray(content)) return null;
66

7-
// We rely on CSS Grid to replicate the 12-column layout.
8-
// RGL config was: rowHeight={30}, margin={[10, 10]}
9-
// CSS Grid gap should be 20px (10px * 2) to approximate RGL margins.
10-
117
return (
128
<div className="w-full max-w-[1200px] mx-auto p-4">
139
<div
1410
style={{
1511
display: 'grid',
1612
gridTemplateColumns: 'repeat(12, 1fr)',
17-
gridAutoRows: '30px', // Matches the Editor's rowHeight
18-
gap: '10px 20px', // Row gap 10px, Col gap 20px
13+
gridAutoRows: '30px',
14+
gap: '10px 20px',
1915
}}
2016
>
2117
{content.map((widget) => {
@@ -30,12 +26,9 @@ const BlogRenderer = ({ content }) => {
3026

3127
return (
3228
<div key={widget.id} style={style} className="overflow-hidden">
33-
{/* TEXT WIDGET RENDERER */}
3429
{widget.type === 'text' && (
3530
<div
3631
className="ql-editor p-0 h-full w-full"
37-
// Using dangerouslySetInnerHTML to render the HTML string from Quill
38-
// In production, consider using DOMPurify.sanitize(widget.content)
3932
dangerouslySetInnerHTML={{ __html: widget.content }}
4033
style={{ color: 'inherit', overflowY: 'auto' }}
4134
/>

frontend/src/components/GridEditor/GridEditor.jsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const useContainerWidth = () => {
2020
for (let entry of entries) {
2121
if (entry.contentRect) {
2222
const newWidth = Math.floor(entry.contentRect.width);
23-
// Threshold to prevent loops
2423
setWidth(prev => {
2524
if (Math.abs(prev - newWidth) > 5) {
2625
return newWidth;
@@ -43,16 +42,9 @@ const useContainerWidth = () => {
4342

4443

4544
const GridEditor = ({ widgets, setWidgets, readOnly = false }) => {
46-
// SIMPLIfIED: Using data-grid approach. No local layouts state.
4745
const { width, ref: containerRef } = useContainerWidth();
4846

49-
const onLayoutChange = (layout) => {
50-
// No-op for state. RGL manages visual state internally.
51-
// We only care about the final result in onDragStop.
52-
};
53-
5447
const onLayoutStop = (layout) => {
55-
// Sync the new layout positions back to the main widgets state
5648
const updatedWidgets = widgets.map(w => {
5749
const l = layout.find(item => item.i === w.id);
5850
if (l) {

frontend/src/components/GridEditor/ImageWidget.jsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ const ImageWidget = ({ url, readOnly }) => {
77
src={url}
88
alt="Post content"
99
className="w-full h-full object-cover pointer-events-none"
10-
// pointer-events-none is important so the drag handler of the grid works on the item body if needed,
11-
// but usually RGL uses a handle.
12-
// If we want to drag by the image content, we might need to disable pointer events or handle them carefully.
1310
/>
1411
</div>
1512
)

frontend/src/components/GridEditor/TextWidget.jsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,27 @@ import 'quill/dist/quill.snow.css';
66
const modules = {
77
toolbar: [
88
[{ 'header': [1, 2, 3, false] }],
9-
[{ 'align': [] }], // Added Alignment
9+
[{ 'align': [] }],
1010
['bold', 'italic', 'underline', 'strike', 'blockquote'],
1111
[{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'indent': '-1' }, { 'indent': '+1' }],
12-
['link', 'clean'] // Removed image/video since we have widgets for that
12+
['link', 'clean']
1313
],
1414
};
1515

1616
const formats = [
17-
'header', 'align', // Added Format
17+
'header', 'align',
1818
'bold', 'italic', 'underline', 'strike', 'blockquote',
1919
'list', 'bullet', 'indent',
2020
'link'
2121
];
2222

2323
const TextWidget = ({ id, content, onChange, readOnly = false }) => {
24-
// Quill uses HTML strings.
2524
const safeContent = Array.isArray(content) ? '' : content;
2625

2726
return (
2827
<div className="h-full w-full flex flex-col bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 overflow-hidden"
2928
style={{ cursor: 'text' }}
30-
onMouseDown={(e) => e.stopPropagation()} /* Allow clicking into editor */
29+
onMouseDown={(e) => e.stopPropagation()}
3130
>
3231
<ReactQuill
3332
theme="snow"

frontend/src/css/login.css

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* Login.css */
21
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
32

43
body {
@@ -7,7 +6,6 @@ body {
76
}
87

98
.login-container {
10-
/* Deep Dark Gradient Background */
119
background: linear-gradient(135deg, #0f172a 0%, #000000 100%);
1210
height: 100vh;
1311
width: 100vw;
@@ -18,7 +16,6 @@ body {
1816
overflow: hidden;
1917
}
2018

21-
/* Optional: Adds a subtle background glow effect */
2219
.login-container::before {
2320
content: '';
2421
position: absolute;
@@ -31,15 +28,14 @@ body {
3128
}
3229

3330
.login-card {
34-
/* Glassmorphism Effect */
35-
background: rgba(30, 41, 59, 0.4); /* Semi-transparent dark blue/slate */
36-
backdrop-filter: blur(12px); /* The blur effect */
31+
background: rgba(30, 41, 59, 0.4);
32+
backdrop-filter: blur(12px);
3733
-webkit-backdrop-filter: blur(12px);
38-
39-
border: 1px solid rgba(255, 255, 255, 0.1); /* Subtle border */
34+
35+
border: 1px solid rgba(255, 255, 255, 0.1);
4036
padding: 3.5rem 2.5rem;
4137
border-radius: 24px;
42-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.8); /* Deep shadow */
38+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.8);
4339

4440
display: flex;
4541
flex-direction: column;
@@ -56,7 +52,6 @@ body {
5652
font-weight: 700;
5753
margin: 0;
5854

59-
/* Gradient Text */
6055
background: linear-gradient(to right, #fff 0%, #a5b4fc 100%);
6156
-webkit-background-clip: text;
6257
-webkit-text-fill-color: transparent;
@@ -66,7 +61,7 @@ body {
6661
}
6762

6863
.login-subtitle {
69-
color: #94a3b8; /* Muted slate text */
64+
color: #94a3b8;
7065
font-size: 0.95rem;
7166
margin-top: -1.5rem;
7267
margin-bottom: 0.5rem;
@@ -79,7 +74,6 @@ body {
7974
justify-content: center;
8075
}
8176

82-
/* Ensure the Google Button container has a minimum height to prevent layout shift */
8377
#googleSignInDiv {
8478
min-height: 44px;
8579
}

frontend/src/index.css

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
--font-serif: "Source Serif 4", ui-serif, Georgia;
77
}
88

9-
/* Add this to force Tailwind to recognize the .dark class */
109
@variant dark (&:where(.dark, .dark *));
1110

1211
@layer base {
@@ -15,14 +14,12 @@
1514
}
1615
}
1716

18-
/* Default: show text */
1917
.sidebar-brand .brand-text {
2018
font-size: 1.4rem;
2119
font-weight: 700;
2220
white-space: nowrap;
2321
}
2422

25-
/* Hide text when sidebar is narrow */
2623
.sidebar.sidebar-narrow-unfoldable:not(:hover) .sidebar-brand .brand-text {
2724
display: none;
2825
}

frontend/src/pages/CreatePost.jsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import React, { useState, useEffect, useRef } from 'react' // Import React and useRef
1+
import React, { useState, useEffect, useRef } from 'react'
22
import { useParams, useNavigate } from "react-router-dom";
33
import api from '../api/axios'
44
import axios from 'axios'
55
import GridEditor from '../components/GridEditor/GridEditor'
66
import { v4 as uuidv4 } from 'uuid';
77

8-
// --- CONSTANTS ---
98
const initialWidgets = [
109
{
1110
id: 'init-1',
@@ -16,7 +15,6 @@ const initialWidgets = [
1615
]
1716

1817

19-
// --- LOCAL STYLED COMPONENTS ---
2018
const ToolbarContainer = ({ children }) => (
2119
<div className="flex flex-wrap gap-2 items-center pb-4 mb-4 border-b border-slate-200 dark:border-slate-700/50 transition-colors duration-300">
2220
{children}
@@ -69,7 +67,6 @@ const CreatePost = () => {
6967
}
7068
}, [isDark]);
7169

72-
// File Input Ref for robust handling
7370
const fileInputRef = useRef(null);
7471

7572
useEffect(() => {
@@ -82,10 +79,8 @@ const CreatePost = () => {
8279

8380
const loadedContent = res.data.blog.content;
8481

85-
// MIGRATION / ADAPTER LOGIC
8682
if (Array.isArray(loadedContent) && loadedContent.length > 0) {
8783
if (loadedContent[0].layout && loadedContent[0].id) {
88-
// Widget format present. Ensure text content is string (Quill) not object (Slate)
8984
const fixedWidgets = loadedContent.map(w => ({
9085
...w,
9186
layout: {
@@ -95,7 +90,6 @@ const CreatePost = () => {
9590
}));
9691
setWidgets(fixedWidgets);
9792
} else {
98-
// Old Slate JSON (pure array)
9993
setWidgets([{
10094
id: uuidv4(),
10195
type: 'text',
@@ -117,12 +111,11 @@ const CreatePost = () => {
117111
}, [id, isEditMode]);
118112

119113

120-
// --- UPLOAD & ADD WIDGET LOGIC ---
121114
const addTextWidget = () => {
122115
const newWidget = {
123116
id: uuidv4(),
124117
type: 'text',
125-
content: '', // Quill starts empty
118+
content: '',
126119
layout: { x: 0, y: Infinity, w: 12, h: 4 }
127120
};
128121
setWidgets([...widgets, newWidget]);
@@ -190,12 +183,10 @@ const CreatePost = () => {
190183
}
191184

192185
try {
193-
// Validate and Sanitize widgets
194186
const sanitizedWidgets = widgets.map(w => ({
195187
...w,
196188
layout: {
197189
...w.layout,
198-
// KEEP Infinity — react-grid-layout understands it
199190
y: w.layout.y
200191
}
201192
}));

frontend/src/pages/HomeFeed.jsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,36 +41,33 @@ export default function HomeFeed() {
4141
const [posts, setPosts] = useState([]);
4242
const [showDeleteModal, setShowDeleteModal] = useState(false);
4343
const [postToDeleteId, setPostToDeleteId] = useState(null);
44-
const [postToDeleteTitle, setPostToDeleteTitle] = useState(''); // To display in modal
44+
const [postToDeleteTitle, setPostToDeleteTitle] = useState('');
4545

4646
const navigate = useNavigate();
4747

4848
const editPost = (postId) => {
4949
navigate(`/edit/${postId}`);
5050
};
5151

52-
// Modified deletePost to show modal
5352
const deletePost = async (postId, postTitle) => {
5453
setPostToDeleteId(postId);
5554
setPostToDeleteTitle(postTitle);
5655
setShowDeleteModal(true);
5756
}
5857

59-
// Function called when user confirms in the modal
6058
const confirmDelete = async () => {
6159
if (!postToDeleteId) return;
6260

6361
try {
64-
// Assuming 'api.get' is correct for your backend's delete endpoint
6562
let res = await api.get(`/api/blog/deleteblog/${postToDeleteId}`)
66-
setPosts(posts.filter(item => item._id !== postToDeleteId)); // Use strict equality
63+
setPosts(posts.filter(item => item._id !== postToDeleteId));
6764
console.log("Post deleted.");
6865
setShowDeleteModal(false);
6966
setPostToDeleteId(null);
7067
setPostToDeleteTitle('');
7168
} catch (e) {
7269
console.error('error deleting post', e);
73-
setShowDeleteModal(false); // Close modal even on error
70+
setShowDeleteModal(false);
7471
}
7572
};
7673

@@ -164,7 +161,6 @@ export default function HomeFeed() {
164161
>
165162
<div className="flex flex-col gap-2">
166163

167-
{/* Icons container - Positioned Absolutely in the top-right corner */}
168164
<div className="absolute top-4 right-4 flex gap-3 text-sm">
169165
{/* Edit Icon */}
170166
<i
@@ -177,13 +173,13 @@ export default function HomeFeed() {
177173
title="Edit Post"
178174
></i>
179175

180-
{/* Delete Icon - Now triggers modal */}
176+
{/* Delete Icon */}
181177
<i
182178
className="bi bi-trash3 hover:text-red-500 transition-colors cursor-pointer text-slate-400 dark:text-slate-500"
183179
onClick={(e) => {
184180
e.preventDefault();
185181
e.stopPropagation();
186-
deletePost(post._id, post.title); // Pass title as well
182+
deletePost(post._id, post.title);
187183
}}
188184
title="Delete Post"
189185
></i>
@@ -227,7 +223,6 @@ export default function HomeFeed() {
227223
</div>
228224
</main>
229225

230-
{/* Render the modal */}
231226
<DeleteConfirmationModal
232227
show={showDeleteModal}
233228
onClose={closeDeleteModal}

0 commit comments

Comments
 (0)