chore: setup project for production
This commit is contained in:
155
app/accounts/login/page.jsx
Normal file
155
app/accounts/login/page.jsx
Normal file
@@ -0,0 +1,155 @@
|
||||
"use client";
|
||||
|
||||
import MainContext from "@/app/contexts/mainContext";
|
||||
import Image from "next/image";
|
||||
import React, { useContext, useState } from "react";
|
||||
|
||||
const LoginSignup = () => {
|
||||
const [isLogin, setIsLogin] = useState(true);
|
||||
const { loginUser, registerUser } = useContext(MainContext);
|
||||
const [formData, setFormData] = useState({
|
||||
email: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
if (isLogin) {
|
||||
loginUser(formData);
|
||||
} else {
|
||||
registerUser(formData);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMode = () => {
|
||||
setIsLogin(!isLogin);
|
||||
setFormData({ email: "", password: "", confirmPassword: "" });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-gray-100">
|
||||
{/* Left section with video */}
|
||||
<div className="hidden lg:flex lg:w-[60%] bg-cover bg-center">
|
||||
<video
|
||||
src="/loginvideo.mp4"
|
||||
className="object-cover w-full h-full"
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
>
|
||||
<source src="/loginvideo.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
{/* Right section with login/signup form */}
|
||||
<div className="w-full lg:w-1/2 flex items-center justify-center p-8 ">
|
||||
<div className="max-w-md w-full space-y-8 bg-white p-7">
|
||||
<div className="flex gap-4 items-center justify-center">
|
||||
<Image
|
||||
src={"/logo1.jpg"}
|
||||
height={200}
|
||||
width={200}
|
||||
alt="logo"
|
||||
className="h-16 w-16 text-center "
|
||||
/>
|
||||
<h1 className="text-[#AC8C6B] text-3xl">{`${
|
||||
isLogin ? "Login" : "Sign up"
|
||||
}`}</h1>
|
||||
</div>
|
||||
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
|
||||
<div className="rounded-md shadow-sm -space-y-px flex flex-col gap-5">
|
||||
<div>
|
||||
<label htmlFor="email-address" className="sr-only">
|
||||
Email address
|
||||
</label>
|
||||
<input
|
||||
id="email-address"
|
||||
name="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
className="appearance-none rounded-none relative block w-full px-3 py-3 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-[#C19A5B] focus:border-[#C19A5B] focus:z-10 sm:text-sm"
|
||||
placeholder="Email address"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="password" className="sr-only">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
className="appearance-none rounded-none relative block w-full px-3 py-3 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-[#C19A5B] focus:border-[#C19A5B] focus:z-10 sm:text-sm"
|
||||
placeholder="Password"
|
||||
value={formData.password}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
{!isLogin && (
|
||||
<div>
|
||||
<label htmlFor="confirm-password" className="sr-only">
|
||||
Confirm Password
|
||||
</label>
|
||||
<input
|
||||
id="confirm-password"
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
autoComplete="new-password"
|
||||
required
|
||||
className="appearance-none rounded-none relative block w-full px-3 py-3 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-[#C19A5B] focus:border-[#C19A5B] focus:z-10 sm:text-sm"
|
||||
placeholder="Confirm Password"
|
||||
value={formData.confirmPassword}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="group relative w-full flex justify-center py-2 px-7 border border-transparent text-xl text-[300] font-medium text-white bg-[#C19A5B] hover:bg-[#c49d60] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
{isLogin ? "Login" : "Sign up"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="text-center">
|
||||
<h2 className="text-[#AC8C6B] font-semibold">
|
||||
Manage subscriptions
|
||||
</h2>
|
||||
<h2 className="text-xl my-3">or</h2>
|
||||
<h2 className="capitalize border-2 px-5 py-3">
|
||||
Continue with google
|
||||
</h2>
|
||||
<button
|
||||
onClick={toggleMode}
|
||||
className="font-medium text-[#C19A5B] mt-10"
|
||||
>
|
||||
{isLogin
|
||||
? "Don't have an account? Sign up"
|
||||
: "Already have an account? Sign in"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginSignup;
|
||||
204
app/accounts/profile/addresses/[id]/page.jsx
Normal file
204
app/accounts/profile/addresses/[id]/page.jsx
Normal file
@@ -0,0 +1,204 @@
|
||||
'use client'
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import authAxios from '@/utils/axios';
|
||||
|
||||
const EditAddress = () => {
|
||||
const { id } = useParams();
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [formData, setFormData] = useState({
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
company: '',
|
||||
address: '',
|
||||
apartment: '',
|
||||
city: '',
|
||||
country: '',
|
||||
zipcode: '',
|
||||
phone: ''
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAddress = async () => {
|
||||
try {
|
||||
const response = await authAxios.get(`/account/addresses/${id}/`);
|
||||
setFormData(response.data);
|
||||
} catch (err) {
|
||||
setError('Failed to fetch address details');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
if (id) {
|
||||
fetchAddress();
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
setError('');
|
||||
|
||||
try {
|
||||
await authAxios.put(`/account/addresses/${id}/`, formData);
|
||||
router.push('/accounts/profile/addresses');
|
||||
} catch (err) {
|
||||
setError(err.response?.data?.message || 'Failed to update address');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white p-6 rounded-lg shadow-md">
|
||||
<h2 className="text-2xl font-semibold mb-6">Edit Address</h2>
|
||||
{error && <div className="mb-4 text-red-500">{error}</div>}
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label htmlFor="first_name" className="block text-sm font-medium text-gray-700 mb-1">First name</label>
|
||||
<input
|
||||
type="text"
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
value={formData.first_name}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="last_name" className="block text-sm font-medium text-gray-700 mb-1">Last name</label>
|
||||
<input
|
||||
type="text"
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
value={formData.last_name}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="company" className="block text-sm font-medium text-gray-700 mb-1">Company</label>
|
||||
<input
|
||||
type="text"
|
||||
id="company"
|
||||
name="company"
|
||||
value={formData.company}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="address" className="block text-sm font-medium text-gray-700 mb-1">Address</label>
|
||||
<input
|
||||
type="text"
|
||||
id="address"
|
||||
name="address"
|
||||
value={formData.address}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="apartment" className="block text-sm font-medium text-gray-700 mb-1">Apartment, suite, etc.</label>
|
||||
<input
|
||||
type="text"
|
||||
id="apartment"
|
||||
name="apartment"
|
||||
value={formData.apartment}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="city" className="block text-sm font-medium text-gray-700 mb-1">City</label>
|
||||
<input
|
||||
type="text"
|
||||
id="city"
|
||||
name="city"
|
||||
value={formData.city}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="country" className="block text-sm font-medium text-gray-700 mb-1">Country/Region</label>
|
||||
<select
|
||||
id="country"
|
||||
name="country"
|
||||
value={formData.country}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
>
|
||||
<option value="">Select a country</option>
|
||||
<option value="IN">India</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="zipcode" className="block text-sm font-medium text-gray-700 mb-1">Postal/Zip Code</label>
|
||||
<input
|
||||
type="text"
|
||||
id="zipcode"
|
||||
name="zipcode"
|
||||
value={formData.zipcode}
|
||||
onChange={handleChange}
|
||||
className="w-full p-2 border border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="phone" className="block text-sm font-medium text-gray-700 mb-1">Phone</label>
|
||||
<div className="flex">
|
||||
<select className="p-2 border border-gray-300 rounded-l" style={{width: '80px'}}>
|
||||
<option value="IN">🇮🇳 +91</option>
|
||||
</select>
|
||||
<input
|
||||
type="tel"
|
||||
id="phone"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
className="flex-grow p-2 border border-gray-300 rounded-r"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end space-x-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push('/accounts/profile/addresses')}
|
||||
className="px-4 py-2 border border-gray-300 rounded text-gray-700 hover:bg-gray-50"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="px-4 py-2 bg-[#96724f] text-white rounded hover:bg-[#AC8C6B] disabled:opacity-50"
|
||||
>
|
||||
{loading ? 'Updating...' : 'Update Address'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditAddress;
|
||||
16
app/accounts/profile/addresses/page.jsx
Normal file
16
app/accounts/profile/addresses/page.jsx
Normal file
@@ -0,0 +1,16 @@
|
||||
'use client'
|
||||
import Addresses from '@/components/accounts/addresses';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
const Page = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
{/* <Asddresses/> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
113
app/accounts/profile/change-password/page.jsx
Normal file
113
app/accounts/profile/change-password/page.jsx
Normal file
@@ -0,0 +1,113 @@
|
||||
'use client'
|
||||
import React, { useState } from "react";
|
||||
import axios from "axios";
|
||||
import authAxios from "@/utils/axios";
|
||||
|
||||
const ChangePassword = () => {
|
||||
const [oldPassword, setOldPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [confirmNewPassword, setConfirmNewPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const [success, setSuccess] = useState("");
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
if (!oldPassword || !newPassword || !confirmNewPassword) {
|
||||
setError("All fields are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (newPassword !== confirmNewPassword) {
|
||||
setError("New passwords do not match.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
setError("");
|
||||
|
||||
try {
|
||||
|
||||
const response = await authAxios.post(
|
||||
"/account/change-password/",
|
||||
{
|
||||
old_password: oldPassword,
|
||||
new_password: newPassword,
|
||||
confirm_new_password: confirmNewPassword,
|
||||
}
|
||||
);
|
||||
|
||||
if (response.data.status) {
|
||||
setSuccess("Password updated successfully.");
|
||||
} else {
|
||||
setError(response.data.message || "Something went wrong.");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Failed to change password. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="text-3xl font-semibold border-b pb-4 text-zinc-700">
|
||||
Change Password
|
||||
</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="sm:w-3/4 p-4">
|
||||
<label className="block font-medium my-3 text-zinc-700 sm:text-xl text-lg">
|
||||
Old Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
className="mt-1 block w-full sm:w-3/5 rounded-md p-3 border"
|
||||
value={oldPassword}
|
||||
onChange={(e) => setOldPassword(e.target.value)}
|
||||
/>
|
||||
|
||||
<label className="block font-medium my-3 text-zinc-700 sm:text-xl text-lg">
|
||||
New Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
className="mt-1 block w-full sm:w-3/5 rounded-md p-3 border"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
/>
|
||||
|
||||
<label className="block my-3 font-medium text-zinc-700 sm:text-xl text-lg">
|
||||
Confirm New Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
className="mt-1 block w-full sm:w-3/5 rounded-md p-3 border"
|
||||
value={confirmNewPassword}
|
||||
onChange={(e) => setConfirmNewPassword(e.target.value)}
|
||||
/>
|
||||
|
||||
{error && (
|
||||
<div className="text-red-600 mt-2">
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{success && (
|
||||
<div className="text-green-600 mt-2">
|
||||
<p>{success}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-[#AC8C6B] bg-opacity-70 text-white px-4 py-3 rounded-md mt-3"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangePassword;
|
||||
12
app/accounts/profile/edit-profile/page.jsx
Normal file
12
app/accounts/profile/edit-profile/page.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import EditProfile from '@/components/accounts/editProfile'
|
||||
import React from 'react'
|
||||
|
||||
const page = () => {
|
||||
return (
|
||||
<div>
|
||||
<EditProfile/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default page
|
||||
20
app/accounts/profile/layout.jsx
Normal file
20
app/accounts/profile/layout.jsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import AccountSidebar from "@/components/accounts/AccountSidebar";
|
||||
import Link from "next/link";
|
||||
|
||||
export const metadata = {
|
||||
title: "Accounts",
|
||||
};
|
||||
|
||||
export default function layout({ children }) {
|
||||
return (
|
||||
<div className='bg-slate-50'>
|
||||
<div className="flex flex-col sm:flex-row min-h-screen bg-gray-100 max-w-7xl mx-auto">
|
||||
{/* Sidebar - flex row on mobile, column on desktop */}
|
||||
<AccountSidebar />
|
||||
|
||||
{/* Main content */}
|
||||
<main className="flex-1 p-8">{children}</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
12
app/accounts/profile/new-address/page.jsx
Normal file
12
app/accounts/profile/new-address/page.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import AddNewAddress from '@/components/accounts/AddNewAddress'
|
||||
import React from 'react'
|
||||
|
||||
const page = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* <AddNewAddress /> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default page
|
||||
120
app/accounts/profile/orders/page.jsx
Normal file
120
app/accounts/profile/orders/page.jsx
Normal file
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
import { useCurrency } from "@/app/contexts/currencyContext";
|
||||
import authAxios, { backendUrl } from "@/utils/axios";
|
||||
import { ShoppingBag } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const OrdersPage = () => {
|
||||
const [orders, setOrders] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { isLoading, formatPrice } = useCurrency();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchOrders = async () => {
|
||||
try {
|
||||
const response = await authAxios.get("/orders/my-orders");
|
||||
setOrders(response.data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching orders:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
fetchOrders();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[40vh]">
|
||||
Loading...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!orders.length) {
|
||||
return (
|
||||
<div>
|
||||
<h1 className="text-3xl font-semibold border-b pb-4 text-zinc-700">
|
||||
Orders
|
||||
</h1>
|
||||
<div className="flex flex-col gap-5 justify-center items-center min-h-[40vh]">
|
||||
<h2>
|
||||
<ShoppingBag className="sm:ml-20 mb-3 text-[#AC8C6B]" />
|
||||
You don't have any orders yet
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="text-3xl font-semibold border-b pb-4 text-zinc-700">
|
||||
Orders
|
||||
</h1>
|
||||
<div className="mt-6 space-y-4">
|
||||
{orders.map((order) => (
|
||||
<div key={order.id} className="bg-white p-4 rounded-lg shadow">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="font-medium">Order #{order.order_number}</span>
|
||||
<span
|
||||
className={`px-3 py-1 rounded-full text-sm ${
|
||||
order.status === "DELIVERED"
|
||||
? "bg-green-100 text-green-800"
|
||||
: order.status === "SHIPPED"
|
||||
? "bg-blue-100 text-blue-800"
|
||||
: "bg-yellow-100 text-yellow-800"
|
||||
}`}
|
||||
>
|
||||
{order.status}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{order.items.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-4">
|
||||
<Image
|
||||
src={`${backendUrl}${item.variant.product.images[0].image}`}
|
||||
alt={item.variant.product.product_name}
|
||||
width={64}
|
||||
height={64}
|
||||
className="object-cover rounded-md"
|
||||
/>
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
{item.variant.product.product_name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-600">
|
||||
Size: {item.variant.size.size_name}
|
||||
{item.design && ` • Design: ${item.design.design_name}`}
|
||||
</p>
|
||||
<p className="text-sm text-gray-600">
|
||||
Quantity: {item.quantity}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 pt-4 border-t flex justify-between items-center">
|
||||
<div className="text-gray-600">
|
||||
{new Date(order.created_at).toLocaleDateString()}
|
||||
</div>
|
||||
<div className="font-medium">
|
||||
Total:{" "}
|
||||
{isLoading ? (
|
||||
<span>Loading...</span>
|
||||
) : (
|
||||
<span>{formatPrice(order.total_amount)}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrdersPage;
|
||||
151
app/accounts/profile/page.jsx
Normal file
151
app/accounts/profile/page.jsx
Normal file
@@ -0,0 +1,151 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import authAxios from "@/utils/axios";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function ProfilePage() {
|
||||
const [profileData, setProfileData] = useState(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isError, setIsError] = useState(false);
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
const fetchProfileData = async () => {
|
||||
try {
|
||||
const response = await authAxios.get("/account/profile/");
|
||||
setProfileData(response.data);
|
||||
setIsLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Error fetching profile data", error);
|
||||
setIsError(true);
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProfileData();
|
||||
}, []);
|
||||
|
||||
const getDisplayValue = (value) => {
|
||||
return value ? value : "Not set up";
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return <div>Error loading profile data. Please try again later.</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-h-[70vh] hide-navbar overflow-y-scroll">
|
||||
<div className="flex gap-3">
|
||||
<div className="p-6 sm:text-xl border">
|
||||
All Orders{" "}
|
||||
<h2 className="text-lg sm:text-2xl font-semibold">
|
||||
{profileData.orders || 0}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-6 border rounded-md sm:text-xl ">
|
||||
Addresses{" "}
|
||||
<h2 className="text-lg sm:text-2xl font-semibold">
|
||||
{profileData.addresses || 0}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold mb-4 mt-4">Profile information</h1>
|
||||
<div className="bg-white shadow-md rounded p-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
First name
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.first_name)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Last name
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.last_name)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Date of birth
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.birth_day)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Gender
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.gender)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="text-xl font-bold mt-6 mb-4">Contact methods</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Email
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.email)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Phone
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.phone)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="text-xl font-bold mt-6 mb-4">Other Info</h2>
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Profile Picture
|
||||
</label>
|
||||
{profileData.profile_pic ? (
|
||||
<Image
|
||||
src={profileData.profile_pic}
|
||||
alt="Profile Picture"
|
||||
width={64}
|
||||
height={64}
|
||||
className="rounded-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<p className="text-gray-900">Not set up</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h2 className="text-xl font-bold mt-6 mb-4">Other Info</h2>
|
||||
<div>
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
Accepts Marketing from Gupta Rudraksha
|
||||
</label>
|
||||
<p className="text-gray-900">
|
||||
{getDisplayValue(profileData.accepts_marketing)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => router.push("/accounts/profile/edit-profile")}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-6"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user