Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion backend/zato-csm-backend/config/supabase.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
from dotenv import load_dotenv
from fastapi import HTTPException

load_dotenv()
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env"))
# print("SUPABASE_URL:", os.getenv("SUPABASE_URL"))
# print("SUPABASE_SERVICE_KEY:", os.getenv("SUPABASE_SERVICE_KEY"))


SUPABASE_URL = os.getenv("SUPABASE_URL")
SUPABASE_SERVICE_KEY = os.getenv("SUPABASE_SERVICE_KEY")
Expand Down
1 change: 0 additions & 1 deletion backend/zato-csm-backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
# --- Swagger Bearer Token Support ---
from fastapi.openapi.utils import get_openapi


def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
Expand Down
2 changes: 1 addition & 1 deletion backend/zato-csm-backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ supabase_auth==2.12.3
supabase_functions==0.10.1
urllib3==2.5.0
websockets==15.0.1
cloudinary==1.44.0
cloudinary==1.44.0
1 change: 1 addition & 0 deletions frontend/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@
--sidebar-border: #f1c658;
--sidebar-ring: #e28e18;
}

93 changes: 64 additions & 29 deletions frontend/src/app/new-product/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import ImagesUploader from '@/components/new-product/ImagesUploader';
import NewProductForm from '@/components/new-product/NewProductForm';
import { useAuth } from '@/context/auth-store';
import { productsAPI } from '@/services/api.service';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import ProductInfoForm from '@/components/new-product/ProductInfoForm';

const NewProductPage: React.FC = () => {
const router = useRouter();
Expand Down Expand Up @@ -91,47 +94,79 @@ const NewProductPage: React.FC = () => {
}
};

const validationSchema = Yup.object().shape({
name: Yup.string().required('Name is required'),
unit: Yup.string().required('Unit is required'),
price: Yup.number()
.typeError('Price must be a number')
.positive('Price must be greater than 0')
.required('Price is required'),
inventoryQuantity: Yup.number()
.typeError('Inventory must be a number')
.integer('Inventory must be an integer')
.min(0, 'Inventory must be 0 or more')
.required('Inventory is required'),
category: Yup.string().required('Category is required'),
});

const initialValues = {
productType: 'Physical Product',
name: '',
description: '',
location: '',
unit: 'Per item',
weight: '',
price: '',
inventoryQuantity: '',
lowStockAlert: '',
sku: '',
category: '',
};

return (
<div className='min-h-screen bg-bg-main'>
<div className="min-h-screen bg-bg-main">
<Header
onBack={() => router.push('/inventory')}
onSave={() => setSubmitSignal((s) => s + 1)}
saving={saving}
error={error}
/>

<div className='px-4 py-6 mx-auto max-w-7xl sm:px-6 lg:px-8'>
<div className='grid grid-cols-1 gap-8 lg:grid-cols-2'>
<div className='space-y-6'>
<ImagesUploader
files={files}
onAddFiles={handleAddFiles}
onRemove={handleRemoveFile}
/>
<NewProductForm
existingCategories={existingCategories}
unitOptions={unitOptions}
productTypeOptions={productTypeOptions}
onSubmit={onSubmit}
submitSignal={submitSignal}
/>

</div>

<div className='space-y-6'>
<div className='p-6 border rounded-lg shadow-sm bg-bg-surface border-[#CBD5E1]'>
<label className='block mb-2 text-sm font-medium text-text-primary'>
Locations
</label>
<div className='text-sm text-text-secondary'>
Set location in the form on the left.
<div className="px-4 py-6 mx-auto max-w-7xl sm:px-6 lg:px-8">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
>
{(formik) => (
<Form>
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
<div className="space-y-6">
<ImagesUploader
files={files}
onAddFiles={handleAddFiles}
onRemove={handleRemoveFile}
/>

<ProductInfoForm
formik={formik}
existingCategories={existingCategories}
/>
</div>

<NewProductForm
formik={formik}
unitOptions={unitOptions}
productTypeOptions={productTypeOptions}
/>
</div>
</div>
</div>
</div>
</Form>
)}
</Formik>
</div>
</div>
);
};

export default NewProductPage;

60 changes: 25 additions & 35 deletions frontend/src/components/new-product/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import { FaRegFolder } from "react-icons/fa6";
import { IoMdArrowRoundBack } from "react-icons/io";

type Props = {
onBack: () => void;
Expand All @@ -10,61 +11,50 @@ type Props = {

const Header: React.FC<Props> = ({ onBack, onSave, saving, error }) => {
return (
<div className="flex items-center justify-between h-16 px-6 border-b border-[#CBD5E1] bg-[#FFFFFF]">
<div className="flex items-center space-x-4">
<button
onClick={onBack}
className="p-2 transition-colors rounded-full hover:bg-gray-50 md:hidden"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="text-zatobox-900"
>
<path d="M15 18l-6-6 6-6" />
</svg>
</button>
<h1 className="text-xl font-semibold text-zatobox-900 md:hidden">
New Product
</h1>
</div>
<div className="flex flex-col sm:flex-row items-center justify-between h-auto sm:h-16 px-4 sm:px-6 py-4 sm:py-0 border-b border-[#CBD5E1] bg-white gap-4 sm:gap-0">
<div className="flex items-center w-full sm:w-auto gap-2">
{/* Botón siempre visible */}
<button
onClick={onBack}
className="p-2 transition-colors rounded-full hover:bg-gray-50 flex-shrink-0"
>
<IoMdArrowRoundBack className="w-6 h-6 text-[#F88612]" />
</button>

{/* Título con margen responsivo */}
<h1 className="text-xl font-semibold text-[#F88612] ml-2 sm:ml-4 md:ml-0">
New Product
</h1>
</div>

<div className="flex items-center space-x-4">
<div className="w-[158px] h-[40px] flex items-center justify-center bg-[#FFFFFF] rounded-lg border border-[#CBD5E1] gap-2">
<span className="text-[#000000] font-medium">Status:</span>
<div className="flex flex-col sm:flex-row items-center space-y-2 sm:space-y-0 sm:space-x-3 w-full sm:w-auto">
<div className="w-full sm:w-[158px] h-[40px] flex items-center justify-center bg-white rounded-lg border border-[#CBD5E1] gap-2">
<span className="text-black font-medium">Status:</span>
<span className="text-[#F88612] font-medium">Active</span>
</div>

{error && <div className="text-sm text-red-500">{error}</div>}

<button
onClick={() => console.log("Delete pressed")}
className="bg-[#A94D14] hover:bg-[#8A3D16] text-[#FFFFFF] font-semibold px-6 py-2 rounded-lg transition-colors flex items-center space-x-2"
className="bg-[#A94D14] hover:bg-[#8A3D16] text-white font-semibold px-6 py-2 rounded-lg transition-colors flex items-center justify-center w-full sm:w-auto"
>
<span>Delete</span>
Delete
</button>

<button
onClick={onSave}
disabled={saving}
className={`bg-[#F88612] hover:bg-[#D9740F] text-[#FFFFFF] font-semibold
rounded-lg transition-colors flex items-center justify-center space-x-1
w-[82px] h-[40px] ${
saving ? "opacity-50 cursor-not-allowed" : ""
}`}
className={`bg-[#F88612] hover:bg-[#D9740F] text-white font-semibold rounded-lg transition-colors flex items-center justify-center space-x-1 w-full sm:w-[82px] h-[40px] ${
saving ? "opacity-50 cursor-not-allowed" : ""
}`}
>
{saving ? (
<div className="w-4 h-4 border-b-2 border-white rounded-full animate-spin"></div>
) : (
<>
<FaRegFolder className="w-4 h-4 self-center" />
<span >Save</span>
<span>Save</span>
</>
)}
</button>
Expand Down
Loading