Skip to content

Commit 40c44d1

Browse files
committed
clean up code,add category chips, fix header UI
1 parent a440b5c commit 40c44d1

12 files changed

Lines changed: 151 additions & 298 deletions

File tree

backend/controllers/userController.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ const authUser = async (req, res) => {
2828
const registerUser = async (req, res) => {
2929
const { name, email, password } = req.body;
3030

31-
if (!email.includes('@') || !email.includes('.')) {
31+
const atIndex = email.indexOf('@');
32+
const dotIndex = email.lastIndexOf('.');
33+
if (atIndex < 1 || dotIndex < atIndex + 2 || dotIndex === email.length - 1) {
3234
return res.status(400).json({ message: 'Please enter a valid email' });
3335
}
3436

frontend/src/Preview.jsx

Lines changed: 53 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,63 @@
1-
import React from 'react';
2-
31
export default function Preview() {
42
return (
5-
<div style={styles.page}>
6-
<div style={styles.bg} />
7-
<div style={styles.content}>
8-
<div style={styles.brand}>
9-
<span style={styles.brandZ}>Z</span>appify
3+
<div style={{
4+
minHeight: '100vh',
5+
display: 'flex',
6+
alignItems: 'center',
7+
justifyContent: 'center',
8+
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
9+
fontFamily: 'sans-serif',
10+
padding: '40px 20px',
11+
flexDirection: 'column',
12+
}}>
13+
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '12px' }}>
14+
<div style={{ fontSize: '36px', fontWeight: '900', color: '#fff', letterSpacing: '-1px' }}>
15+
<span style={{ color: '#e85d04' }}>Z</span>appify
1016
</div>
11-
<p style={styles.tagline}>Premium Shoe Store</p>
12-
<div style={styles.phoneWrap}>
13-
<div style={styles.phone}>
14-
<div style={styles.notch} />
15-
<div style={styles.screen}>
16-
<iframe
17-
src="/"
18-
style={styles.iframe}
19-
title="Zappify App"
20-
/>
17+
<p style={{ color: 'rgba(255,255,255,0.5)', fontSize: '14px', margin: 0, letterSpacing: '2px', textTransform: 'uppercase' }}>
18+
Premium Shoe Store
19+
</p>
20+
21+
<div style={{ marginTop: '20px', filter: 'drop-shadow(0 40px 80px rgba(0,0,0,0.7))' }}>
22+
<div style={{
23+
width: '393px',
24+
height: '852px',
25+
background: '#1a1a1a',
26+
borderRadius: '54px',
27+
padding: '14px',
28+
border: '2px solid rgba(255,255,255,0.15)',
29+
position: 'relative',
30+
display: 'flex',
31+
flexDirection: 'column',
32+
alignItems: 'center',
33+
boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.05), 0 0 0 1px #000',
34+
}}>
35+
<div style={{ position: 'absolute', left: '-3px', top: '120px', width: '3px', height: '36px', background: '#333', borderRadius: '2px 0 0 2px' }} />
36+
<div style={{ position: 'absolute', left: '-3px', top: '170px', width: '3px', height: '64px', background: '#333', borderRadius: '2px 0 0 2px' }} />
37+
<div style={{ position: 'absolute', left: '-3px', top: '248px', width: '3px', height: '64px', background: '#333', borderRadius: '2px 0 0 2px' }} />
38+
<div style={{ position: 'absolute', right: '-3px', top: '180px', width: '3px', height: '80px', background: '#333', borderRadius: '0 2px 2px 0' }} />
39+
40+
<div style={{ flex: 1, width: '100%', borderRadius: '42px', overflow: 'hidden', background: '#fff', position: 'relative' }}>
41+
<div style={{
42+
position: 'absolute',
43+
top: '14px',
44+
left: '50%',
45+
transform: 'translateX(-50%)',
46+
width: '120px',
47+
height: '34px',
48+
background: '#000',
49+
borderRadius: '20px',
50+
zIndex: 100,
51+
}} />
52+
<div style={{ paddingTop: '58px', height: '100%', boxSizing: 'border-box' }}>
53+
<iframe src="/" style={{ width: '100%', height: '100%', border: 'none' }} title="Zappify App" />
54+
</div>
2155
</div>
22-
<div style={styles.homeBar} />
56+
57+
<div style={{ width: '134px', height: '5px', background: 'rgba(255,255,255,0.4)', borderRadius: '3px', marginTop: '10px' }} />
2358
</div>
2459
</div>
2560
</div>
2661
</div>
2762
);
2863
}
29-
30-
const styles = {
31-
page: {
32-
minHeight: '100vh',
33-
display: 'flex',
34-
alignItems: 'center',
35-
justifyContent: 'center',
36-
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
37-
fontFamily: 'sans-serif',
38-
padding: '40px 20px',
39-
flexDirection: 'column',
40-
},
41-
bg: {
42-
position: 'fixed',
43-
inset: 0,
44-
background: 'radial-gradient(ellipse at 20% 50%, rgba(232,93,4,0.15) 0%, transparent 60%), radial-gradient(ellipse at 80% 20%, rgba(100,100,255,0.1) 0%, transparent 60%)',
45-
pointerEvents: 'none',
46-
},
47-
content: {
48-
display: 'flex',
49-
flexDirection: 'column',
50-
alignItems: 'center',
51-
gap: '12px',
52-
position: 'relative',
53-
zIndex: 1,
54-
},
55-
brand: {
56-
fontSize: '36px',
57-
fontWeight: '900',
58-
color: '#fff',
59-
letterSpacing: '-1px',
60-
},
61-
brandZ: {
62-
color: '#e85d04',
63-
},
64-
tagline: {
65-
color: 'rgba(255,255,255,0.5)',
66-
fontSize: '14px',
67-
margin: 0,
68-
letterSpacing: '2px',
69-
textTransform: 'uppercase',
70-
},
71-
phoneWrap: {
72-
marginTop: '20px',
73-
filter: 'drop-shadow(0 40px 80px rgba(0,0,0,0.6))',
74-
},
75-
phone: {
76-
width: '375px',
77-
height: '780px',
78-
background: '#111',
79-
borderRadius: '50px',
80-
padding: '12px',
81-
border: '2px solid rgba(255,255,255,0.1)',
82-
position: 'relative',
83-
display: 'flex',
84-
flexDirection: 'column',
85-
alignItems: 'center',
86-
},
87-
notch: {
88-
width: '120px',
89-
height: '28px',
90-
background: '#111',
91-
borderRadius: '0 0 20px 20px',
92-
position: 'absolute',
93-
top: '12px',
94-
left: '50%',
95-
transform: 'translateX(-50%)',
96-
zIndex: 10,
97-
},
98-
screen: {
99-
flex: 1,
100-
width: '100%',
101-
borderRadius: '40px',
102-
overflow: 'hidden',
103-
background: '#fff',
104-
},
105-
iframe: {
106-
width: '100%',
107-
height: '100%',
108-
border: 'none',
109-
},
110-
homeBar: {
111-
width: '120px',
112-
height: '4px',
113-
background: 'rgba(255,255,255,0.3)',
114-
borderRadius: '2px',
115-
marginTop: '8px',
116-
},
117-
};

frontend/src/components/AccountModal.jsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from 'react';
1+
import { useState } from 'react';
22
import { motion, AnimatePresence } from 'framer-motion';
33
import { X, Package, LogOut, ArrowLeft, ChevronRight } from 'lucide-react';
44

@@ -13,10 +13,7 @@ const CANCEL_REASONS = [
1313

1414
const TRACKING_STEPS = ['Order Placed', 'Shipped', 'In-Transit', 'Out For Delivery', 'Delivered'];
1515

16-
const formatDate = (dateStr) => {
17-
const d = new Date(dateStr);
18-
return d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' });
19-
};
16+
const formatDate = (dateStr) => new Date(dateStr).toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' });
2017

2118
const getEstDelivery = (dateStr) => {
2219
const d = new Date(dateStr);
@@ -25,7 +22,7 @@ const getEstDelivery = (dateStr) => {
2522
};
2623

2724
const AccountModal = ({ user, onClose, onLogout, orders, onCancelOrder }) => {
28-
const [view, setView] = useState('main'); // main | detail | cancel | cancelled
25+
const [view, setView] = useState('main');
2926
const [selectedOrder, setSelectedOrder] = useState(null);
3027
const [cancelReason, setCancelReason] = useState('');
3128
const [remarks, setRemarks] = useState('');
@@ -67,12 +64,10 @@ const AccountModal = ({ user, onClose, onLogout, orders, onCancelOrder }) => {
6764
</div>
6865

6966
<div className="account-body">
70-
71-
{/* ── MAIN VIEW ── */}
7267
{view === 'main' && (
7368
<>
7469
<div className="account-profile-card">
75-
<img src={user.picture} alt={user.name} className="account-avatar" />
70+
<img src={user.picture || `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=e85d04&color=fff`} alt={user.name} className="account-avatar" />
7671
<div>
7772
<p className="account-name">{user.name}</p>
7873
<p className="account-email">{user.email}</p>
@@ -115,7 +110,6 @@ const AccountModal = ({ user, onClose, onLogout, orders, onCancelOrder }) => {
115110
</>
116111
)}
117112

118-
{/* ── ORDER DETAIL VIEW ── */}
119113
{view === 'detail' && selectedOrder && (
120114
<div className="order-detail-view">
121115
<div className="od-header">
@@ -136,7 +130,6 @@ const AccountModal = ({ user, onClose, onLogout, orders, onCancelOrder }) => {
136130
</div>
137131
</div>
138132

139-
{/* Tracking */}
140133
{selectedOrder.status !== 'Cancelled' ? (
141134
<div className="od-tracking">
142135
{TRACKING_STEPS.map((step, i) => (
@@ -159,7 +152,6 @@ const AccountModal = ({ user, onClose, onLogout, orders, onCancelOrder }) => {
159152
</div>
160153
)}
161154

162-
{/* ── CANCEL VIEW ── */}
163155
{view === 'cancel' && selectedOrder && (
164156
<div className="cancel-view">
165157
<div className="od-header">
@@ -194,10 +186,8 @@ const AccountModal = ({ user, onClose, onLogout, orders, onCancelOrder }) => {
194186
</div>
195187
</div>
196188
)}
197-
198189
</div>
199190

200-
{/* Confirmation Popup */}
201191
<AnimatePresence>
202192
{showConfirmPopup && (
203193
<motion.div className="cancel-popup-overlay" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>

frontend/src/components/Checkout.jsx

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import React, { useState } from 'react';
1+
import { useState } from 'react';
22
import { motion, AnimatePresence } from 'framer-motion';
3-
import { X, ChevronRight, MapPin, CreditCard, ShoppingBag, Check } from 'lucide-react';
3+
import { X, ChevronRight, MapPin, CreditCard, Check } from 'lucide-react';
44

55
const STEPS = ['MY BAG', 'ADDRESS', 'PAYMENT'];
66

7-
const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
7+
const Checkout = ({ cartItems, onClose, onOrderPlaced }) => {
88
const [step, setStep] = useState(0);
99
const [address, setAddress] = useState({ name: '', phone: '', pincode: '', city: '', state: '', street: '' });
1010
const [paymentMethod, setPaymentMethod] = useState('cod');
@@ -23,11 +23,7 @@ const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
2323
return (
2424
<div className="checkout-overlay">
2525
<div className="checkout-modal">
26-
<motion.div
27-
className="order-success"
28-
initial={{ scale: 0.8, opacity: 0 }}
29-
animate={{ scale: 1, opacity: 1 }}
30-
>
26+
<motion.div className="order-success" initial={{ scale: 0.8, opacity: 0 }} animate={{ scale: 1, opacity: 1 }}>
3127
<div className="success-icon"><Check size={40} /></div>
3228
<h2>Order Placed!</h2>
3329
<p>Your order has been placed successfully. You'll receive a confirmation soon.</p>
@@ -40,36 +36,26 @@ const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
4036

4137
return (
4238
<div className="checkout-overlay">
43-
<motion.div
44-
className="checkout-modal"
45-
initial={{ opacity: 0, y: 40 }}
46-
animate={{ opacity: 1, y: 0 }}
47-
exit={{ opacity: 0, y: 40 }}
48-
>
49-
{/* Header */}
39+
<motion.div className="checkout-modal" initial={{ opacity: 0, y: 40 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 40 }}>
5040
<div className="checkout-header">
5141
<h2>CHECKOUT</h2>
5242
<button className="close-btn" onClick={onClose}><X size={22} /></button>
5343
</div>
5444

55-
{/* Steps */}
5645
<div className="checkout-steps">
5746
{STEPS.map((s, i) => (
58-
<React.Fragment key={s}>
47+
<div key={s} style={{ display: 'flex', alignItems: 'center', flex: i < STEPS.length - 1 ? 1 : 'none' }}>
5948
<div className={`step-item ${i <= step ? 'active' : ''} ${i < step ? 'done' : ''}`}>
6049
<div className="step-circle">{i < step ? <Check size={14} /> : i + 1}</div>
6150
<span>{s}</span>
6251
</div>
6352
{i < STEPS.length - 1 && <div className={`step-line ${i < step ? 'done' : ''}`} />}
64-
</React.Fragment>
53+
</div>
6554
))}
6655
</div>
6756

68-
{/* Step Content */}
6957
<div className="checkout-body">
7058
<AnimatePresence mode="wait">
71-
72-
{/* STEP 1: MY BAG */}
7359
{step === 0 && (
7460
<motion.div key="bag" initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }}>
7561
<div className="co-items">
@@ -103,7 +89,6 @@ const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
10389
</motion.div>
10490
)}
10591

106-
{/* STEP 2: ADDRESS */}
10792
{step === 1 && (
10893
<motion.div key="address" initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }}>
10994
<div className="co-address-form">
@@ -121,23 +106,19 @@ const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
121106
</div>
122107
<div className="co-btn-row">
123108
<button className="btn-outline co-back-btn" onClick={() => setStep(0)}>BACK</button>
124-
<button
125-
className="btn-primary co-next-btn"
126-
onClick={() => {
127-
if (!address.name || !address.phone || !address.street || !address.city || !address.pincode) {
128-
alert('Please fill all required fields');
129-
return;
130-
}
131-
setStep(2);
132-
}}
133-
>
109+
<button className="btn-primary co-next-btn" onClick={() => {
110+
if (!address.name || !address.phone || !address.street || !address.city || !address.pincode) {
111+
alert('Please fill all required fields');
112+
return;
113+
}
114+
setStep(2);
115+
}}>
134116
PROCEED TO PAYMENT <ChevronRight size={18} />
135117
</button>
136118
</div>
137119
</motion.div>
138120
)}
139121

140-
{/* STEP 3: PAYMENT */}
141122
{step === 2 && (
142123
<motion.div key="payment" initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }}>
143124
<div className="co-payment">
@@ -154,7 +135,6 @@ const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
154135
</label>
155136
))}
156137
</div>
157-
158138
<div className="co-billing">
159139
<h4>ORDER SUMMARY</h4>
160140
<div className="billing-row"><span>Cart Total</span><span>{cartTotal.toLocaleString('en-IN')}</span></div>
@@ -164,13 +144,10 @@ const Checkout = ({ cartItems, onClose, onRemoveFromCart, onOrderPlaced }) => {
164144
</div>
165145
<div className="co-btn-row">
166146
<button className="btn-outline co-back-btn" onClick={() => setStep(1)}>BACK</button>
167-
<button className="btn-primary co-next-btn place-order-btn" onClick={handlePlaceOrder}>
168-
PLACE ORDER
169-
</button>
147+
<button className="btn-primary co-next-btn place-order-btn" onClick={handlePlaceOrder}>PLACE ORDER</button>
170148
</div>
171149
</motion.div>
172150
)}
173-
174151
</AnimatePresence>
175152
</div>
176153
</motion.div>

0 commit comments

Comments
 (0)