Upload files to "/"
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import cloudinary
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
cloudinary.config(
|
||||
cloud_name=os.getenv("CLOUDINARY_CLOUD_NAME"),
|
||||
api_key=os.getenv("CLOUDINARY_API_KEY"),
|
||||
api_secret=os.getenv("CLOUDINARY_API_SECRET")
|
||||
)
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
#datatbase.py
|
||||
|
||||
import os
|
||||
import psycopg2
|
||||
from psycopg2 import OperationalError
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
from sqlalchemy.engine.url import URL
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load env variables
|
||||
load_dotenv()
|
||||
|
||||
# Neon DB credentials
|
||||
DB_NAME = os.getenv("DB_NAME")
|
||||
DB_USER = os.getenv("DB_USER")
|
||||
DB_PASSWORD = os.getenv("DB_PASSWORD")
|
||||
DB_HOST = os.getenv("DB_HOST")
|
||||
DB_PORT = os.getenv("DB_PORT", "5432")
|
||||
|
||||
# Create DATABASE URL
|
||||
DATABASE_URL = URL.create(
|
||||
drivername="postgresql",
|
||||
username=DB_USER,
|
||||
password=DB_PASSWORD,
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
database=DB_NAME,
|
||||
query={
|
||||
"sslmode": "require" # 🔥 MUST for Neon
|
||||
}
|
||||
)
|
||||
|
||||
# Create engine
|
||||
engine = create_engine(
|
||||
DATABASE_URL,
|
||||
pool_pre_ping=True,
|
||||
pool_recycle=300,
|
||||
pool_size=5,
|
||||
max_overflow=10,
|
||||
echo=False
|
||||
)
|
||||
|
||||
# Session
|
||||
SessionLocal = sessionmaker(
|
||||
autoflush=False,
|
||||
autocommit=False,
|
||||
bind=engine
|
||||
)
|
||||
|
||||
# Base model
|
||||
Base = declarative_base()
|
||||
|
||||
# Dependency for FastAPI
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
# Test connection
|
||||
def test_connection():
|
||||
try:
|
||||
connection = psycopg2.connect(
|
||||
host=DB_HOST,
|
||||
database=DB_NAME,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD,
|
||||
port=DB_PORT,
|
||||
sslmode="require"
|
||||
)
|
||||
print("✅ Neon PostgreSQL connection successful!")
|
||||
connection.close()
|
||||
|
||||
except OperationalError as e:
|
||||
print(f"❌ Error: {e}")
|
||||
print("Failed to connect to Neon database.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_connection()
|
||||
@@ -0,0 +1,405 @@
|
||||
from sqlalchemy import Column, Integer, String, Float, Boolean, ForeignKey, DateTime, Text
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Index
|
||||
from database import Base
|
||||
|
||||
# =========================
|
||||
# USER
|
||||
# =========================
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=True)
|
||||
phone = Column(String, unique=True, nullable=False)
|
||||
email = Column(String, unique=True)
|
||||
# 🔥 ADD THESE TWO NEW COLUMNS
|
||||
dob = Column(String, nullable=True)
|
||||
gender = Column(String, nullable=True)
|
||||
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
|
||||
orders = relationship("Order", back_populates="user")
|
||||
|
||||
# 🔥 NEW RELATION
|
||||
addresses = relationship("UserAddress", back_populates="user")
|
||||
|
||||
class UserAddress(Base):
|
||||
__tablename__ = "user_addresses"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
user_id = Column(Integer, ForeignKey("users.id"), index=True)
|
||||
flat = Column(String)
|
||||
building = Column(String)
|
||||
landmark = Column(String)
|
||||
|
||||
lat = Column(Float)
|
||||
lng = Column(Float)
|
||||
|
||||
address_type = Column(String) # HOME / WORK / OTHER
|
||||
|
||||
is_default = Column(Boolean, default=False)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
user = relationship("User", back_populates="addresses")
|
||||
|
||||
# =========================
|
||||
# VENDOR (Kitchen)
|
||||
# =========================
|
||||
class Vendor(Base):
|
||||
__tablename__ = "vendors"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=False)
|
||||
|
||||
# 🔥 FULL ADDRESS (structured)
|
||||
flat = Column(String)
|
||||
building = Column(String)
|
||||
landmark = Column(String)
|
||||
|
||||
location = Column(String) # full readable address
|
||||
|
||||
lat = Column(Float, nullable=False)
|
||||
lng = Column(Float, nullable=False)
|
||||
|
||||
radius = Column(Float, default=2)
|
||||
|
||||
email = Column(String, unique=True)
|
||||
password = Column(String)
|
||||
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_open = Column(Boolean, default=False)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
city = Column(String)
|
||||
zone = Column(String)
|
||||
zonal_admin_id = Column(Integer, ForeignKey("admins.id"))
|
||||
|
||||
|
||||
menus = relationship("VendorMenu", back_populates="vendor")
|
||||
|
||||
|
||||
# =========================
|
||||
# MENU ITEMS (Admin Controlled)
|
||||
# =========================
|
||||
class MenuItem(Base):
|
||||
__tablename__ = "menu_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, nullable=False)
|
||||
category = Column(String)
|
||||
|
||||
description = Column(Text) # 🔥 NEW
|
||||
|
||||
vendor_price = Column(Float, nullable=False)
|
||||
selling_price = Column(Float, nullable=False)
|
||||
image_url = Column(String, nullable=True)
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
vendors = relationship("VendorMenu", back_populates="menu_item")
|
||||
|
||||
|
||||
# =========================
|
||||
# VENDOR MENU (Availability)
|
||||
# =========================
|
||||
class VendorMenu(Base):
|
||||
__tablename__ = "vendor_menu"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
vendor_id = Column(Integer, ForeignKey("vendors.id"), index=True)
|
||||
menu_item_id = Column(Integer, ForeignKey("menu_items.id"), index=True)
|
||||
is_available = Column(Boolean, default=True)
|
||||
|
||||
vendor = relationship("Vendor", back_populates="menus")
|
||||
menu_item = relationship("MenuItem", back_populates="vendors")
|
||||
|
||||
|
||||
# =========================
|
||||
# ORDER
|
||||
# =========================
|
||||
class Order(Base):
|
||||
__tablename__ = "orders"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
batch_id = Column(Integer, ForeignKey("batches.id"), nullable=True, index=True)
|
||||
zonal_admin_id = Column(Integer, ForeignKey("admins.id"), index=True) # ✅ ADD
|
||||
admin = relationship("Admin")
|
||||
user_id = Column(Integer, ForeignKey("users.id"), index=True)
|
||||
user_lat = Column(Float)
|
||||
user_lng = Column(Float)
|
||||
|
||||
# 🔥 ORDER ADDRESS SNAPSHOT
|
||||
address_flat = Column(String, nullable=True)
|
||||
address_building = Column(String, nullable=True)
|
||||
address_landmark = Column(String, nullable=True)
|
||||
address_type = Column(String, nullable=True)
|
||||
|
||||
address_lat = Column(Float, nullable=True)
|
||||
address_lng = Column(Float, nullable=True)
|
||||
|
||||
total_amount = Column(Float, nullable=False)
|
||||
gst = Column(Float, nullable=False)
|
||||
final_amount = Column(Float, nullable=False)
|
||||
|
||||
status = Column(String, default="PLACED", index=True)
|
||||
reject_reason = Column(String, nullable=True) # 🔥 ADD THIS
|
||||
payment_status = Column(String, default="PENDING")
|
||||
delivery = relationship("Delivery", back_populates="order", uselist=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
|
||||
|
||||
user = relationship("User", back_populates="orders")
|
||||
items = relationship("OrderItem", back_populates="order")
|
||||
|
||||
batch = relationship("Batch", back_populates="orders")
|
||||
|
||||
cancel_reason = Column(Text, nullable=True)
|
||||
cancelled_by = Column(String, nullable=True)
|
||||
cancelled_at = Column(DateTime, nullable=True)
|
||||
|
||||
# =========================
|
||||
# ORDER ITEMS (Snapshot)
|
||||
# =========================
|
||||
class OrderItem(Base):
|
||||
__tablename__ = "order_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
order_id = Column(Integer, ForeignKey("orders.id"), index=True)
|
||||
menu_item_id = Column(Integer, ForeignKey("menu_items.id"), index=True)
|
||||
|
||||
vendor_id = Column(Integer, index=True)
|
||||
|
||||
quantity = Column(Integer, nullable=False)
|
||||
|
||||
name = Column(String)
|
||||
vendor_price = Column(Float, nullable=False)
|
||||
selling_price = Column(Float, nullable=False)
|
||||
status = Column(String, default="PREPARING")
|
||||
|
||||
order = relationship("Order", back_populates="items")
|
||||
|
||||
# ✅ MUST BE INSIDE CLASS
|
||||
__table_args__ = (
|
||||
Index("idx_order_vendor", "order_id", "vendor_id"),
|
||||
)
|
||||
|
||||
# =========================
|
||||
# DELIVERY
|
||||
# =========================
|
||||
class Delivery(Base):
|
||||
__tablename__ = "deliveries"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
order_id = Column(Integer, ForeignKey("orders.id"), index=True)
|
||||
delivery_boy_id = Column(Integer, ForeignKey("delivery_boys.id"), index=True)
|
||||
|
||||
status = Column(String, default="ASSIGNED")
|
||||
|
||||
# Payment handling
|
||||
payment_method = Column(String) # COD / QR
|
||||
payment_amount = Column(Float) # ✅ store actual paid amount
|
||||
payment_proof = Column(Text) # image URL / text note
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
|
||||
delivery_boy = relationship("DeliveryBoy")
|
||||
order = relationship("Order", back_populates="delivery")
|
||||
|
||||
|
||||
class Batch(Base):
|
||||
__tablename__ = "batches"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
zonal_admin_id = Column(Integer, ForeignKey("admins.id"), index=True) # ✅ ADD
|
||||
|
||||
status = Column(String, default="CREATED", index=True)
|
||||
# CREATED / ASSIGNED / PICKED_UP / OUT_FOR_DELIVERY / DELIVERED # CREATED / ASSIGNED / PICKED / COMPLETED
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
delivery_boy_id = Column(Integer, ForeignKey("delivery_boys.id"), nullable=True)
|
||||
orders = relationship("Order", back_populates="batch")
|
||||
# ✅ FIX HERE
|
||||
delivery_boy = relationship(
|
||||
"DeliveryBoy",
|
||||
back_populates="batches",
|
||||
foreign_keys=[delivery_boy_id]
|
||||
)
|
||||
|
||||
# =========================
|
||||
# ADMIN (City + Zonal)
|
||||
# =========================
|
||||
class Admin(Base):
|
||||
__tablename__ = "admins"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
name = Column(String, nullable=False)
|
||||
email = Column(String, unique=True, nullable=False)
|
||||
password = Column(String, nullable=False)
|
||||
|
||||
role = Column(String, nullable=False)
|
||||
# CITY_ADMIN / ZONAL_ADMIN
|
||||
|
||||
city = Column(String, nullable=True)
|
||||
zone = Column(String, nullable=True)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
|
||||
|
||||
class DeliveryBoy(Base):
|
||||
__tablename__ = "delivery_boys"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
name = Column(String, nullable=False)
|
||||
email = Column(String, unique=True, nullable=False)
|
||||
phone = Column(String, nullable=False)
|
||||
password = Column(String, nullable=False)
|
||||
|
||||
city = Column(String)
|
||||
zone = Column(String)
|
||||
|
||||
zonal_admin_id = Column(Integer, ForeignKey("admins.id"))
|
||||
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
# 🔥 NEW: STATUS SYSTEM
|
||||
status = Column(String, default="OFFLINE", index=True)
|
||||
# OFFLINE / IDLE / ASSIGNED / PICKED_UP / OUT_FOR_DELIVERY
|
||||
|
||||
# 🔥 NEW: ASSIGNMENT TRACKING (VERY IMPORTANT)
|
||||
current_batch_id = Column(Integer, nullable=True)
|
||||
current_order_id = Column(Integer, nullable=True)
|
||||
|
||||
# 🔥 NEW: LIVE LOCATION (for admin tracking later)
|
||||
lat = Column(Float, nullable=True)
|
||||
lng = Column(Float, nullable=True)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
|
||||
# ✅ ADD THIS (CRITICAL FIX)
|
||||
batches = relationship(
|
||||
"Batch",
|
||||
back_populates="delivery_boy",
|
||||
foreign_keys="Batch.delivery_boy_id"
|
||||
)
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class NotificationToken(Base):
|
||||
|
||||
__tablename__ = "notification_tokens"
|
||||
|
||||
id = Column(
|
||||
Integer,
|
||||
primary_key=True,
|
||||
index=True
|
||||
)
|
||||
|
||||
user_id = Column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
index=True
|
||||
)
|
||||
|
||||
role = Column(
|
||||
String,
|
||||
nullable=False
|
||||
)
|
||||
|
||||
token = Column(
|
||||
Text,
|
||||
unique=True,
|
||||
nullable=False
|
||||
)
|
||||
|
||||
# ✅ DEVICE INFO
|
||||
device_name = Column(String)
|
||||
|
||||
platform = Column(String)
|
||||
|
||||
browser = Column(String)
|
||||
|
||||
# ✅ ACTIVE / LOGOUT SUPPORT
|
||||
is_active = Column(
|
||||
Boolean,
|
||||
default=True
|
||||
)
|
||||
|
||||
created_at = Column(
|
||||
DateTime,
|
||||
default=datetime.utcnow
|
||||
)
|
||||
|
||||
updated_at = Column(
|
||||
DateTime,
|
||||
default=datetime.utcnow,
|
||||
onupdate=datetime.utcnow
|
||||
)
|
||||
|
||||
# =========================
|
||||
# REVIEWS
|
||||
# =========================
|
||||
class Review(Base):
|
||||
__tablename__ = "reviews"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), index=True)
|
||||
order_id = Column(Integer, ForeignKey("orders.id"), unique=True, index=True) # One review per order
|
||||
zonal_admin_id = Column(Integer, ForeignKey("admins.id"), index=True)
|
||||
|
||||
rating = Column(Integer, nullable=False) # 1 to 5 stars
|
||||
comment = Column(Text, nullable=True) # Optional written review
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User")
|
||||
order = relationship("Order")
|
||||
zonal_admin = relationship("Admin")
|
||||
|
||||
|
||||
# =========================
|
||||
# SUPPORT TICKETS
|
||||
# =========================
|
||||
|
||||
class SupportTicket(Base):
|
||||
__tablename__ = "support_tickets"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
user_name = Column(String, nullable=False)
|
||||
mobile_number = Column(String, nullable=False)
|
||||
message = Column(Text, nullable=False)
|
||||
status = Column(String, default="OPEN")
|
||||
# OPEN / CLOSED / IN_PROGRESS
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
frontend_ip = Column(String, nullable=True)
|
||||
backend_ip = Column(String, nullable=True)
|
||||
user = relationship("User")
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
aiohappyeyeballs==2.6.1
|
||||
aiohttp==3.13.1
|
||||
aiosignal==1.4.0
|
||||
annotated-types==0.7.0
|
||||
anyio==4.10.0
|
||||
attrs==25.4.0
|
||||
bcrypt==3.2.2
|
||||
certifi==2025.8.3
|
||||
cffi==2.0.0
|
||||
charset-normalizer==3.4.3
|
||||
click==8.2.1
|
||||
colorama==0.4.6
|
||||
cryptography==45.0.7
|
||||
ecdsa==0.19.1
|
||||
fastapi==0.116.1
|
||||
frozenlist==1.8.0
|
||||
greenlet==3.2.4
|
||||
h11==0.16.0
|
||||
http_ece==1.2.1
|
||||
httptools==0.6.4
|
||||
idna==3.10
|
||||
multidict==6.7.0
|
||||
passlib==1.7.4
|
||||
propcache==0.4.1
|
||||
psycopg2-binary==2.9.10
|
||||
py-vapid==1.9.2
|
||||
pyasn1==0.6.1
|
||||
pycparser==2.23
|
||||
pydantic==2.11.7
|
||||
pydantic_core==2.33.2
|
||||
python-dotenv==1.1.1
|
||||
python-jose==3.5.0
|
||||
python-multipart==0.0.20
|
||||
pywebpush==2.1.1
|
||||
PyYAML==6.0.2
|
||||
requests==2.32.5
|
||||
rsa==4.9.1
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
SQLAlchemy==2.0.43
|
||||
starlette==0.47.3
|
||||
typing-inspection==0.4.1
|
||||
typing_extensions==4.15.0
|
||||
urllib3==2.5.0
|
||||
uvicorn==0.35.0
|
||||
watchfiles==1.1.0
|
||||
websockets==15.0.1
|
||||
yarl==1.22.0
|
||||
Generated
+648
@@ -0,0 +1,648 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@mui/x-date-pickers": "^9.1.0",
|
||||
"dayjs": "^1.11.20",
|
||||
"qrcode.react": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/cache": {
|
||||
"version": "11.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
|
||||
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
"@emotion/sheet": "^1.4.0",
|
||||
"@emotion/utils": "^1.4.2",
|
||||
"@emotion/weak-memoize": "^0.4.0",
|
||||
"stylis": "4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/hash": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
|
||||
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
|
||||
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@emotion/serialize": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
|
||||
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@emotion/hash": "^0.9.2",
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
"@emotion/unitless": "^0.10.0",
|
||||
"@emotion/utils": "^1.4.2",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/sheet": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
|
||||
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@emotion/unitless": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
|
||||
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@emotion/utils": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
|
||||
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@emotion/weak-memoize": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
|
||||
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@mui/core-downloads-tracker": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-9.0.1.tgz",
|
||||
"integrity": "sha512-GzamIIhZ1bH77dq7eKaeyRgJdkypsxin4jBFq2EMs4lBWRR0LFO1CSVMsoebn/VvjcNrnrOrjy48MkrkQUK2iw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/material": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-9.0.1.tgz",
|
||||
"integrity": "sha512-voyCpeUxcSWLN7KPZuq0pGCIt726T9K6kiVM3XUcywZDAlZSarLHaUxJVQpospbjjOzN53hwyjo8s6KoWl6utw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/core-downloads-tracker": "^9.0.1",
|
||||
"@mui/system": "^9.0.1",
|
||||
"@mui/types": "^9.0.0",
|
||||
"@mui/utils": "^9.0.1",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/react-transition-group": "^4.4.12",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.2.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.2.4",
|
||||
"react-transition-group": "^4.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.5.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@mui/material-pigment-css": "^9.0.1",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
},
|
||||
"@mui/material-pigment-css": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/private-theming": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-9.0.1.tgz",
|
||||
"integrity": "sha512-pSIGq4Yw749KHEwlkYZWVERgHgwJELP6ODtBNUfV8V4oIb5H+h7IQDFXuk/b2oQccODK1enJAtiEzlgLZmq+8g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/utils": "^9.0.1",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/styled-engine": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-9.0.0.tgz",
|
||||
"integrity": "sha512-9RLGdX4Jg0aQPRuvqh/OLzYSPlgd5zyEw5/1HIRfdavSiOd03WtUaGZH9/w1RoTYuRKwpgy0hpIFaMHIqPVIWg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@emotion/cache": "^11.14.0",
|
||||
"@emotion/serialize": "^1.3.3",
|
||||
"@emotion/sheet": "^1.4.0",
|
||||
"csstype": "^3.2.3",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.4.1",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/system": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-9.0.1.tgz",
|
||||
"integrity": "sha512-WvlioaLxk6ewUIOfh0StxUvOPDS1mCfzaulcudsL1brZNXuh0N9FMk7RpH7ImJKjEz412SEy/V/yvqmtxbqxCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/private-theming": "^9.0.1",
|
||||
"@mui/styled-engine": "^9.0.0",
|
||||
"@mui/types": "^9.0.0",
|
||||
"@mui/utils": "^9.0.1",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.2.3",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.5.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/types": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-9.0.0.tgz",
|
||||
"integrity": "sha512-i1cuFCAWN44b3AJWO7mh7tuh1sqbQSeVr/94oG0TX5uXivac8XalgE4/6fQZcmGZigzbQ35IXxj/4jLpRIBYZg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/utils": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.0.1.tgz",
|
||||
"integrity": "sha512-f3UO3jNN1pYg5zxqXC81Bvv8hx5ACcYc0387382ZI7M5ono1heIwHYLrKsz85myguWdeVKPRZGmDdynWUBjK2g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/types": "^9.0.0",
|
||||
"@types/prop-types": "^15.7.15",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-date-pickers": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-9.1.0.tgz",
|
||||
"integrity": "sha512-vE2oXP8bAlwppFckOc4HEwbhj5Mz7ZUqKU8kNyDa6v19cYsX3ais+fcuCGMh1xZiO1Q+H97s9xgN3WzzgcfmPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/utils": "9.0.0",
|
||||
"@mui/x-internals": "^9.1.0",
|
||||
"@types/react-transition-group": "^4.4.12",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-transition-group": "^4.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
"@mui/material": "^7.3.0 || ^9.0.0",
|
||||
"@mui/system": "^7.3.0 || ^9.0.0",
|
||||
"date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
|
||||
"date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0",
|
||||
"dayjs": "^1.10.7",
|
||||
"luxon": "^3.0.2",
|
||||
"moment": "^2.29.4",
|
||||
"moment-hijri": "^2.1.2 || ^3.0.0",
|
||||
"moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
},
|
||||
"date-fns": {
|
||||
"optional": true
|
||||
},
|
||||
"date-fns-jalali": {
|
||||
"optional": true
|
||||
},
|
||||
"dayjs": {
|
||||
"optional": true
|
||||
},
|
||||
"luxon": {
|
||||
"optional": true
|
||||
},
|
||||
"moment": {
|
||||
"optional": true
|
||||
},
|
||||
"moment-hijri": {
|
||||
"optional": true
|
||||
},
|
||||
"moment-jalaali": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-date-pickers/node_modules/@mui/utils": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.0.0.tgz",
|
||||
"integrity": "sha512-bQcqyg/gjULUqTuyUjSAFr6LQGLvtkNtDbJerAtoUn9kGZ0hg5QJiN1PLHMLbeFpe3te1831uq7GFl2ITokGdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/types": "^9.0.0",
|
||||
"@types/prop-types": "^15.7.15",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-internals": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-9.1.0.tgz",
|
||||
"integrity": "sha512-fVezTa1lU+Hb3y9UMI8D/iWXADhs0I8PaZqoh2LOUXjGEUJmKqwsRD19ZXInZsH2yu+YS0dqYMPDvzjYTTyo+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/utils": "9.0.0",
|
||||
"reselect": "^5.1.1",
|
||||
"use-sync-external-store": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-internals/node_modules/@mui/utils": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.0.0.tgz",
|
||||
"integrity": "sha512-bQcqyg/gjULUqTuyUjSAFr6LQGLvtkNtDbJerAtoUn9kGZ0hg5QJiN1PLHMLbeFpe3te1831uq7GFl2ITokGdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@mui/types": "^9.0.0",
|
||||
"@types/prop-types": "^15.7.15",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
|
||||
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.20",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz",
|
||||
"integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qrcode.react": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz",
|
||||
"integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.6",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
|
||||
"integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.6",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
|
||||
"integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "19.2.6",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz",
|
||||
"integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.6.0",
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@mui/x-date-pickers": "^9.1.0",
|
||||
"dayjs": "^1.11.20",
|
||||
"qrcode.react": "^4.2.0"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
aiohappyeyeballs==2.6.1
|
||||
aiohttp==3.13.1
|
||||
aiosignal==1.4.0
|
||||
annotated-types==0.7.0
|
||||
anyio==4.10.0
|
||||
attrs==25.4.0
|
||||
bcrypt==3.2.2
|
||||
certifi==2025.8.3
|
||||
cffi==2.0.0
|
||||
charset-normalizer==3.4.3
|
||||
click==8.2.1
|
||||
colorama==0.4.6
|
||||
cryptography==45.0.7
|
||||
ecdsa==0.19.1
|
||||
fastapi==0.116.1
|
||||
frozenlist==1.8.0
|
||||
greenlet==3.2.4
|
||||
h11==0.16.0
|
||||
http_ece==1.2.1
|
||||
httptools==0.6.4
|
||||
idna==3.10
|
||||
multidict==6.7.0
|
||||
passlib==1.7.4
|
||||
propcache==0.4.1
|
||||
psycopg2-binary==2.9.10
|
||||
py-vapid==1.9.2
|
||||
pyasn1==0.6.1
|
||||
pycparser==2.23
|
||||
pydantic==2.11.7
|
||||
pydantic_core==2.33.2
|
||||
python-dotenv==1.1.1
|
||||
python-jose==3.5.0
|
||||
python-multipart==0.0.20
|
||||
pywebpush==2.1.1
|
||||
PyYAML==6.0.2
|
||||
requests==2.32.5
|
||||
rsa==4.9.1
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
SQLAlchemy==2.0.43
|
||||
starlette==0.47.3
|
||||
typing-inspection==0.4.1
|
||||
typing_extensions==4.15.0
|
||||
urllib3==2.5.0
|
||||
uvicorn==0.35.0
|
||||
watchfiles==1.1.0
|
||||
websockets==15.0.1
|
||||
yarl==1.22.0
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import List
|
||||
from typing import Literal
|
||||
|
||||
|
||||
|
||||
class AddressCreate(BaseModel):
|
||||
user_id: int
|
||||
flat: str
|
||||
building: str
|
||||
landmark: str = None
|
||||
lat: float
|
||||
lng: float
|
||||
address_type: Literal["HOME", "WORK", "OTHER"] = "HOME"
|
||||
frontend_ip: str
|
||||
|
||||
class OrderItemRequest(BaseModel):
|
||||
menu_item_id: int
|
||||
quantity: int
|
||||
vendor_id: int
|
||||
|
||||
|
||||
class OrderCreate(BaseModel):
|
||||
frontend_ip: str | None = None
|
||||
|
||||
user_id: int
|
||||
lat: float
|
||||
lng: float
|
||||
items: List[OrderItemRequest]
|
||||
|
||||
|
||||
class AssignDelivery(BaseModel):
|
||||
order_id: int
|
||||
delivery_boy_id: int
|
||||
|
||||
|
||||
class UpdateDeliveryStatus(BaseModel):
|
||||
order_id: int
|
||||
status: str # ASSIGNED / PICKED / DELIVERED
|
||||
|
||||
class DeliveryPayment(BaseModel):
|
||||
order_id: int
|
||||
payment_method: str
|
||||
payment_proof: str | None = None
|
||||
amount: float
|
||||
|
||||
|
||||
# User Login
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
name: str
|
||||
phone: str
|
||||
email: str
|
||||
|
||||
class SendOTP(BaseModel):
|
||||
phone: str
|
||||
|
||||
class VerifyOTP(BaseModel):
|
||||
phone: str
|
||||
otp: str
|
||||
|
||||
name: str = None
|
||||
email: str = None
|
||||
|
||||
# ✅ NEW
|
||||
frontend_ip: str | None = None
|
||||
|
||||
# ================= ADMIN =================
|
||||
|
||||
class AdminLogin(BaseModel):
|
||||
email: str
|
||||
password: str
|
||||
|
||||
|
||||
class CreateZonalAdmin(BaseModel):
|
||||
name: str
|
||||
email: str
|
||||
password: str
|
||||
zone: str
|
||||
|
||||
class VendorCreate(BaseModel):
|
||||
name: str
|
||||
location: str
|
||||
|
||||
flat: str = None
|
||||
building: str = None
|
||||
landmark: str = None
|
||||
lat: float | None = None
|
||||
lng: float | None = None
|
||||
|
||||
email: str
|
||||
password: str
|
||||
|
||||
class DeliveryBoyCreate(BaseModel):
|
||||
name: str
|
||||
email: str
|
||||
phone: str
|
||||
password: str
|
||||
|
||||
class DeliveryBoyLogin(BaseModel):
|
||||
email: str
|
||||
password: str
|
||||
|
||||
frontend_ip: str | None = None
|
||||
|
||||
class ReviewCreate(BaseModel):
|
||||
user_id: int
|
||||
order_id: int
|
||||
rating: int
|
||||
comment: str | None = None
|
||||
|
||||
# =========================
|
||||
# SUPPORT TICKET
|
||||
# =========================
|
||||
|
||||
class SupportTicketCreate(BaseModel):
|
||||
user_id: int
|
||||
message: str
|
||||
frontend_ip: str | None = None
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import math
|
||||
from fastapi import HTTPException
|
||||
|
||||
def haversine(lat1, lon1, lat2, lon2):
|
||||
R = 6371 # Earth radius in KM
|
||||
|
||||
dLat = math.radians(lat2 - lat1)
|
||||
dLon = math.radians(lon2 - lon1)
|
||||
|
||||
a = (
|
||||
math.sin(dLat / 2) ** 2 +
|
||||
math.cos(math.radians(lat1)) *
|
||||
math.cos(math.radians(lat2)) *
|
||||
math.sin(dLon / 2) ** 2
|
||||
)
|
||||
|
||||
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||||
|
||||
return R * c
|
||||
|
||||
|
||||
def calculate_eta(distance):
|
||||
prep_time = 10 # mins
|
||||
travel_time = distance * 5 # mins per km
|
||||
|
||||
eta = prep_time + travel_time
|
||||
|
||||
return f"{int(eta)}-{int(eta + 5)} mins"
|
||||
|
||||
# ================= AUTH =================
|
||||
from passlib.context import CryptContext
|
||||
from jose import jwt
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
SECRET_KEY = "secret123"
|
||||
ALGORITHM = "HS256"
|
||||
|
||||
|
||||
def hash_password(password: str):
|
||||
password = password[:72] # 🔥 FIX
|
||||
return pwd_context.hash(password)
|
||||
|
||||
|
||||
def verify_password(plain, hashed):
|
||||
plain = plain[:72]
|
||||
return pwd_context.verify(plain, hashed)
|
||||
|
||||
|
||||
def create_token(data: dict):
|
||||
to_encode = data.copy()
|
||||
to_encode["exp"] = datetime.utcnow() + timedelta(days=30)
|
||||
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
|
||||
# Admin
|
||||
from fastapi import Depends
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
|
||||
security = HTTPBearer()
|
||||
|
||||
def get_current_admin(
|
||||
credentials: HTTPAuthorizationCredentials = Depends(security)
|
||||
):
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
credentials.credentials,
|
||||
SECRET_KEY,
|
||||
algorithms=[ALGORITHM]
|
||||
)
|
||||
return payload
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid token"
|
||||
)
|
||||
Reference in New Issue
Block a user