From 6b3714f2bce74bd68864098e848ea488465a37bf Mon Sep 17 00:00:00 2001 From: Sidharth Prabhu Date: Mon, 3 Aug 2026 10:41:57 +0530 Subject: [PATCH] User setup added --- api-dashboard/src/App.tsx | 2 +- .../canteen/sales/service/DatabaseSeeder.java | 59 +++- .../src/main/resources/application.properties | 2 +- create_master_user.py | 239 +++++++++++++ ordering_site/src/components/ItemCard.tsx | 2 +- ordering_site/src/index.css | 325 ++++++++++++++++++ ordering_site/src/pages/CheckoutScreen.tsx | 100 +++--- ordering_site/src/pages/StallDetailScreen.css | 17 +- 8 files changed, 692 insertions(+), 54 deletions(-) create mode 100644 create_master_user.py diff --git a/api-dashboard/src/App.tsx b/api-dashboard/src/App.tsx index f478cba3..ae5900db 100644 --- a/api-dashboard/src/App.tsx +++ b/api-dashboard/src/App.tsx @@ -843,7 +843,7 @@ function App() {

๐Ÿ’ก Dev Sandbox Access:

{loginType === 'SYSTEM' ? ( -

Default Admin: admin / Password: admin123

+

Default Admin: admin / Password: admin

) : (

Sign in with your Google account. First-time users will be asked for a mobile number to complete registration.

)} diff --git a/backend/src/main/java/com/rit/canteen/sales/service/DatabaseSeeder.java b/backend/src/main/java/com/rit/canteen/sales/service/DatabaseSeeder.java index 20521144..8d020ecb 100644 --- a/backend/src/main/java/com/rit/canteen/sales/service/DatabaseSeeder.java +++ b/backend/src/main/java/com/rit/canteen/sales/service/DatabaseSeeder.java @@ -2,15 +2,21 @@ package com.rit.canteen.sales.service; import com.rit.canteen.sales.model.BaseItem; import com.rit.canteen.sales.model.Product; +import com.rit.canteen.sales.model.Stall; +import com.rit.canteen.sales.model.SystemUser; import com.rit.canteen.sales.repository.BaseItemRepository; import com.rit.canteen.sales.repository.ProductRepository; +import com.rit.canteen.sales.repository.StallRepository; +import com.rit.canteen.sales.repository.SystemUserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; import org.springframework.jdbc.core.JdbcTemplate; -import java.util.List; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Component; import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; @Component public class DatabaseSeeder implements CommandLineRunner { @@ -21,6 +27,15 @@ public class DatabaseSeeder implements CommandLineRunner { @Autowired private ProductRepository productRepository; + @Autowired + private StallRepository stallRepository; + + @Autowired + private SystemUserRepository systemUserRepository; + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + @Autowired private JdbcTemplate jdbcTemplate; @@ -34,6 +49,8 @@ public class DatabaseSeeder implements CommandLineRunner { repairLobColumns(); seedCategories(); seedProducts(); + seedStalls(); + seedMasterUser(); } private void repairFeedbackSchema() { @@ -254,4 +271,42 @@ public class DatabaseSeeder implements CommandLineRunner { p.setActive(true); return p; } + + private void seedStalls() { + if (stallRepository.count() == 0) { + List allProducts = productRepository.findAll(); + + Stall s1 = new Stall("Main Canteen Stall", "Primary food counter serving meals, fast food, and beverages", null); + Stall s2 = new Stall("Bakery & Juice Counter", "Fresh bakery items, pastries, snacks, and fresh fruit juices", null); + Stall s3 = new Stall("South Indian Express", "Authentic dosas, idlis, vadas, and South Indian breakfast specials", null); + + s1.setProducts(allProducts); + s2.setProducts(allProducts.stream() + .filter(p -> "Bakery & Sweets".equalsIgnoreCase(p.getCategory()) || "Beverages & Drinks".equalsIgnoreCase(p.getCategory()) || "Snacks & Quick Bites".equalsIgnoreCase(p.getCategory())) + .toList()); + s3.setProducts(allProducts.stream() + .filter(p -> "Snacks & Quick Bites".equalsIgnoreCase(p.getCategory()) || "Indian Main Course".equalsIgnoreCase(p.getCategory())) + .toList()); + + stallRepository.saveAll(List.of(s1, s2, s3)); + System.out.println(">>> SEEDED DEFAULT STALLS (Main Canteen, Bakery & Juice Counter, South Indian Express)"); + } + } + + private void seedMasterUser() { + Optional existingAdmin = systemUserRepository.findByEmail("admin"); + if (existingAdmin.isEmpty()) { + SystemUser admin = new SystemUser(); + admin.setName("Admin Master"); + admin.setEmail("admin"); + admin.setPassword(passwordEncoder.encode("admin")); + admin.setRole("MASTER"); + admin.setPermissions(List.of("dashboard", "sale", "customers", "purchases", "inventory", "expense", "reports", "stores", "table", "wallet", "promotions", "feedback")); + admin.setViewOnly(false); + systemUserRepository.save(admin); + System.out.println(">>> SEEDED ADMIN MASTER USER (username: admin, password: admin)"); + } else { + System.out.println(">>> ADMIN MASTER USER EXISTS. Skipping admin user creation."); + } + } } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 8b15d5a8..51318e13 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -27,7 +27,7 @@ app.jwt.expiration-ms=86400000 # Master Account โ€” REQUIRED environment variables # ============================================================ app.master.username=${MASTER_USER:admin} -app.master.password=${MASTER_PASSWORD:admin123} +app.master.password=${MASTER_PASSWORD:admin} # File upload configuration spring.servlet.multipart.max-file-size=10MB diff --git a/create_master_user.py b/create_master_user.py new file mode 100644 index 00000000..4e570ae7 --- /dev/null +++ b/create_master_user.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +""" +Master User Creation Script for Positeasy Canteen Automation System. + +This script creates or updates a master administrator user in the database +with username 'admin' and password 'admin', and synchronizes the application configuration. +""" + +import sys +import os +import re +import argparse +import bcrypt +import psycopg2 + +# Default Configuration +DEFAULT_USERNAME = "admin" +DEFAULT_PASSWORD = "admin" +DEFAULT_NAME = "Admin Master" +DEFAULT_ROLE = "MASTER" + +DEFAULT_DB_HOST = "localhost" +DEFAULT_DB_PORT = 5432 +DEFAULT_DB_NAME = "positeasy" +DEFAULT_DB_USER = "postgres" +DEFAULT_DB_PASS = "sidharth" + +ALL_PERMISSIONS = [ + "dashboard", + "sale", + "customers", + "purchases", + "inventory", + "expense", + "reports", + "stores", + "table", + "wallet", + "promotions", + "feedback" +] + +def hash_password(password: str) -> str: + """Hash password using bcrypt compatible with Spring Security BCryptPasswordEncoder.""" + salt = bcrypt.gensalt(rounds=10) + hashed = bcrypt.hashpw(password.encode('utf-8'), salt) + return hashed.decode('utf-8') + +def parse_application_properties(prop_path: str) -> dict: + """Parse db credentials from backend application.properties if available.""" + config = {} + if not os.path.exists(prop_path): + return config + + with open(prop_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, value = line.split('=', 1) + config[key.strip()] = value.strip() + return config + +def update_application_properties(prop_path: str, username: str, password: str) -> bool: + """Update app.master.username and app.master.password in application.properties.""" + if not os.path.exists(prop_path): + print(f"โš ๏ธ [Config] File not found: {prop_path}") + return False + + with open(prop_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Update or add app.master.username and app.master.password + new_user_line = f"app.master.username=${{MASTER_USER:{username}}}" + new_pass_line = f"app.master.password=${{MASTER_PASSWORD:{password}}}" + + if re.search(r'^app\.master\.username=.*$', content, flags=re.MULTILINE): + content = re.sub(r'^app\.master\.username=.*$', new_user_line, content, flags=re.MULTILINE) + else: + content += f"\n{new_user_line}" + + if re.search(r'^app\.master\.password=.*$', content, flags=re.MULTILINE): + content = re.sub(r'^app\.master\.password=.*$', new_pass_line, content, flags=re.MULTILINE) + else: + content += f"\n{new_pass_line}" + + with open(prop_path, 'w', encoding='utf-8') as f: + f.write(content) + + print(f"โœ… [Config] Updated {prop_path} with default master credentials ({username}/{password}).") + return True + +def update_frontend_demo_credentials(app_tsx_path: str, username: str, password: str) -> bool: + """Update UI demo credentials displayed in api-dashboard if file exists.""" + if not os.path.exists(app_tsx_path): + return False + + with open(app_tsx_path, 'r', encoding='utf-8') as f: + content = f.read() + + old_pattern = r'Default Admin:\s*[^<]*\s*/\s*Password:\s*[^<]*' + new_text = f'Default Admin: {username} / Password: {password}' + + if re.search(old_pattern, content): + content = re.sub(old_pattern, new_text, content) + with open(app_tsx_path, 'w', encoding='utf-8') as f: + f.write(content) + print(f"โœ… [UI] Updated demo credentials in {app_tsx_path}.") + return True + return False + +def create_or_update_master_user(db_params: dict, username: str, password: str, name: str) -> bool: + """Insert or update master user in PostgreSQL database.""" + print(f"\n๐Ÿ”Œ Connecting to PostgreSQL database '{db_params['dbname']}' on {db_params['host']}:{db_params['port']}...") + + try: + conn = psycopg2.connect(**db_params) + conn.autocommit = False + cur = conn.cursor() + + # Check if system_users table exists + cur.execute(""" + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = 'system_users' + ); + """) + table_exists = cur.fetchone()[0] + + if not table_exists: + print("โŒ Table 'system_users' does not exist in the database. Has backend schema initialized?") + conn.close() + return False + + # Check if master user with this username (stored in email column) exists + cur.execute("SELECT id, name, role FROM system_users WHERE email = %s;", (username,)) + row = cur.fetchone() + + hashed_pass = hash_password(password) + + if row: + user_id = row[0] + print(f"๐Ÿ”„ Existing master user found (ID: {user_id}). Updating credentials...") + cur.execute(""" + UPDATE system_users + SET name = %s, password = %s, role = %s, view_only = false + WHERE id = %s; + """, (name, hashed_pass, DEFAULT_ROLE, user_id)) + else: + print(f"โž• Creating new master user '{username}'...") + cur.execute(""" + INSERT INTO system_users (name, email, password, role, view_only) + VALUES (%s, %s, %s, %s, false) + RETURNING id; + """, (name, username, hashed_pass, DEFAULT_ROLE)) + user_id = cur.fetchone()[0] + + # Reset permissions for this user + cur.execute("DELETE FROM system_user_permissions WHERE user_id = %s;", (user_id,)) + for perm in ALL_PERMISSIONS: + cur.execute(""" + INSERT INTO system_user_permissions (user_id, permission) + VALUES (%s, %s); + """, (user_id, perm)) + + conn.commit() + + # Verification query + cur.execute(""" + SELECT u.id, u.name, u.email, u.role, count(p.permission) + FROM system_users u + LEFT JOIN system_user_permissions p ON u.id = p.user_id + WHERE u.id = %s + GROUP BY u.id, u.name, u.email, u.role; + """, (user_id,)) + ver = cur.fetchone() + cur.close() + conn.close() + + print("\n" + "=" * 50) + print("๐ŸŽ‰ MASTER USER CREATED / UPDATED SUCCESSFULLY") + print("=" * 50) + print(f" User ID: {ver[0]}") + print(f" Name: {ver[1]}") + print(f" Username: {ver[2]}") + print(f" Password: {password}") + print(f" Role: {ver[3]}") + print(f" Permissions: {ver[4]} granted ({', '.join(ALL_PERMISSIONS[:4])}...)") + print("=" * 50 + "\n") + return True + + except Exception as e: + print(f"โŒ Database error: {e}") + return False + +def main(): + parser = argparse.ArgumentParser(description="Create or update master user for Positeasy Canteen Automation.") + parser.add_argument("-u", "--username", default=DEFAULT_USERNAME, help="Master username (default: admin)") + parser.add_argument("-p", "--password", default=DEFAULT_PASSWORD, help="Master password (default: admin)") + parser.add_argument("-n", "--name", default=DEFAULT_NAME, help="Display name for master user") + parser.add_argument("--host", default=DEFAULT_DB_HOST, help="PostgreSQL host (default: localhost)") + parser.add_argument("--port", type=int, default=DEFAULT_DB_PORT, help="PostgreSQL port (default: 5432)") + parser.add_argument("--dbname", default=DEFAULT_DB_NAME, help="PostgreSQL database name (default: positeasy)") + parser.add_argument("--dbuser", default=DEFAULT_DB_USER, help="PostgreSQL database user (default: postgres)") + parser.add_argument("--dbpass", default=DEFAULT_DB_PASS, help="PostgreSQL database password") + + args = parser.parse_args() + + project_root = os.path.dirname(os.path.abspath(__file__)) + prop_path = os.path.join(project_root, "backend", "src", "main", "resources", "application.properties") + app_tsx_path = os.path.join(project_root, "api-dashboard", "src", "App.tsx") + + db_params = { + "host": args.host, + "port": args.port, + "dbname": args.dbname, + "user": args.dbuser, + "password": args.dbpass + } + + print("๐Ÿš€ Starting Master User setup script...") + + # 1. Database creation / update + db_success = create_or_update_master_user(db_params, args.username, args.password, args.name) + + # 2. Sync application.properties + update_application_properties(prop_path, args.username, args.password) + + # 3. Sync frontend dashboard UI + update_frontend_demo_credentials(app_tsx_path, args.username, args.password) + + if db_success: + print("โœจ All steps completed successfully! You can now log in with:") + print(f" Username: {args.username}") + print(f" Password: {args.password}") + else: + print("โš ๏ธ Database operation failed or incomplete. Check database connectivity.") + +if __name__ == "__main__": + main() diff --git a/ordering_site/src/components/ItemCard.tsx b/ordering_site/src/components/ItemCard.tsx index 2b887b83..64343929 100644 --- a/ordering_site/src/components/ItemCard.tsx +++ b/ordering_site/src/components/ItemCard.tsx @@ -97,7 +97,7 @@ const ItemCard: React.FC = ({ item, isLast, variant = 'list' }) = ) : (
๐Ÿฒ
)} - {item.isPopular && Bestseller} + {item.isPopular && item.stock !== 0 && Bestseller} {item.stock === 0 && Sold Out}
diff --git a/ordering_site/src/index.css b/ordering_site/src/index.css index 577f11c7..b7177521 100644 --- a/ordering_site/src/index.css +++ b/ordering_site/src/index.css @@ -267,3 +267,328 @@ main::-webkit-scrollbar { .veg-nonveg-indicator.non-veg .dot { background-color: #ef4444; } + +/* DESKTOP SCREEN OPTIMIZATIONS */ +@media (min-width: 769px) { + body { + display: block; + background-color: var(--surface); + } + + .container { + max-width: 100% !important; + width: 100% !important; + margin: 0 !important; + height: auto !important; + min-height: 100vh !important; + border-radius: 0 !important; + border: none !important; + box-shadow: none !important; + background-color: var(--surface) !important; + } + + main { + overflow-y: visible !important; + } + + /* Home Screen layout adjustments */ + .welcome-section { + display: flex !important; + justify-content: space-between !important; + align-items: center !important; + padding: 32px 60px 16px !important; + } + + .search-bar-container { + padding: 16px 60px 24px !important; + } + + .search-bar { + max-width: 550px !important; + } + + /* Grid listings on desktop - Full Width */ + .categories-grid { + grid-template-columns: repeat(10, 1fr) !important; + gap: 20px !important; + padding: 0 60px 24px !important; + } + + .category-image-wrapper { + max-width: 90px !important; + max-height: 90px !important; + } + + .stalls-carousel { + display: grid !important; + grid-template-columns: repeat(4, 1fr) !important; + gap: 24px !important; + padding: 16px 60px 24px !important; + overflow-x: visible !important; + } + + .stall-card { + min-width: 100% !important; + max-width: 100% !important; + height: 200px !important; + } + + .popular-carousel { + display: grid !important; + grid-template-columns: repeat(5, 1fr) !important; + gap: 24px !important; + padding: 16px 60px 24px !important; + overflow-x: visible !important; + } + + /* Multi-column items listing */ + .recommended-section .items-list, + .search-results-section .items-list, + .stall-items-section .items-list { + display: grid !important; + grid-template-columns: repeat(3, 1fr) !important; + gap: 24px !important; + padding: 16px 60px 24px !important; + } + + .section-header { + padding: 24px 60px 12px !important; + } + + /* Floating Pill Bottom Navigation Bar */ + .bottom-nav { + position: fixed !important; + bottom: 24px !important; + left: 50% !important; + transform: translateX(-50%) !important; + width: 500px !important; + border-radius: 100px !important; + box-shadow: 0 10px 40px rgba(44, 58, 42, 0.15) !important; + border: 1px solid var(--border) !important; + height: 64px !important; + padding-bottom: 0 !important; + z-index: 1001 !important; + background: var(--surface) !important; + } + + /* Redesigned Item Detail Page for Desktop */ + .item-detail-page { + display: flex !important; + flex-direction: column !important; + padding: 0 !important; + height: auto !important; + } + + .item-detail-page .detail-header-overlay { + position: static !important; + width: 100% !important; + border-bottom: 1px solid var(--border) !important; + } + + .item-detail-page main { + display: flex !important; + flex-direction: row !important; + gap: 40px !important; + padding: 40px 60px !important; + align-items: flex-start !important; + } + + .item-detail-page .item-hero { + flex: 1 !important; + height: 480px !important; + border-radius: 20px !important; + box-shadow: 0 10px 30px rgba(44, 58, 42, 0.08) !important; + overflow: hidden !important; + } + + .item-detail-page .item-hero-image { + width: 100% !important; + height: 100% !important; + object-fit: cover !important; + } + + .item-detail-page .item-details-content { + flex: 1.2 !important; + margin-top: 0 !important; + padding: 0 !important; + background: transparent !important; + box-shadow: none !important; + border-radius: 0 !important; + } + + .item-detail-page .item-name-large { + font-size: 2.2rem !important; + font-weight: 850 !important; + color: var(--text-dark) !important; + } + + .item-detail-page .item-subtitle { + font-size: 1rem !important; + color: var(--primary) !important; + font-weight: 700 !important; + } + + .item-detail-page .item-long-description { + font-size: 0.95rem !important; + line-height: 1.6 !important; + color: var(--text-mid) !important; + margin-bottom: 24px !important; + } + + .item-detail-page .item-extra-info { + background: var(--primary-light) !important; + border-radius: 16px !important; + padding: 20px !important; + border: 1px solid var(--border) !important; + margin-bottom: 24px !important; + } + + .item-detail-page .item-footer { + position: static !important; + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + background: var(--surface) !important; + border: 1px solid var(--border) !important; + border-radius: 20px !important; + padding: 20px 24px !important; + box-shadow: var(--shadow) !important; + margin-top: 24px !important; + } + + .item-detail-page .footer-price-info { + display: flex !important; + flex-direction: column !important; + } + + .item-detail-page .total-label { + font-size: 0.8rem !important; + text-transform: uppercase !important; + letter-spacing: 0.5px !important; + } + + .item-detail-page .total-value { + font-size: 1.8rem !important; + font-weight: 850 !important; + color: var(--primary) !important; + } + + .item-detail-page .primary-action-button { + height: 48px !important; + padding: 0 32px !important; + font-size: 0.95rem !important; + border-radius: 100px !important; + width: auto !important; + min-width: 160px !important; + } + + /* Stall Detail Page Split Flow */ + .stall-detail-page main.detail-content { + display: flex !important; + gap: 40px !important; + padding: 24px 60px !important; + align-items: flex-start !important; + } + + .stall-main-card { + flex: 1 !important; + max-width: 320px !important; + margin: 0 !important; + position: sticky !important; + top: 24px !important; + background: var(--surface) !important; + padding: 24px !important; + border-radius: 20px !important; + border: 1px solid var(--border) !important; + box-shadow: var(--shadow) !important; + z-index: 100 !important; + } + + .stall-items-section { + flex: 2.2 !important; + padding: 0 !important; + } + + .stall-items-section .section-title { + padding: 0 0 16px 0 !important; + } + + .stall-items-section .items-list { + display: grid !important; + grid-template-columns: repeat(2, 1fr) !important; + gap: 20px !important; + padding: 0 !important; + } + + /* Cart split flow */ + .cart-page main { + display: flex !important; + gap: 40px !important; + padding: 24px 60px !important; + align-items: flex-start !important; + } + + .cart-items-section { + flex: 1.6 !important; + } + + .bill-details { + flex: 1 !important; + margin-top: 0 !important; + background: var(--surface) !important; + padding: 24px !important; + border-radius: 16px !important; + border: 1px solid var(--border) !important; + box-shadow: var(--shadow) !important; + } + + .cart-footer { + padding: 20px 60px !important; + border-top: 1px solid var(--border) !important; + } + + /* Checkout split flow */ + .checkout-page main { + display: flex !important; + gap: 40px !important; + padding: 24px 60px !important; + align-items: flex-start !important; + } + + .checkout-section { + flex: 1.6 !important; + margin-bottom: 0 !important; + background: transparent !important; + } + + .checkout-summary-container-desktop { + flex: 1 !important; + display: flex !important; + flex-direction: column !important; + gap: 24px !important; + } + + .checkout-page .order-summary-mini, + .checkout-page .insufficient-warning-premium { + margin: 0 !important; + background: var(--surface) !important; + padding: 24px !important; + border-radius: 16px !important; + border: 1px solid var(--border) !important; + box-shadow: var(--shadow) !important; + } + + /* Handle footer buttons in desktop splits */ + .checkout-footer { + display: none !important; + } + + .desktop-checkout-action { + display: block !important; + } +} + +/* Hide desktop checkout actions on mobile */ +.desktop-checkout-action { + display: none; +} diff --git a/ordering_site/src/pages/CheckoutScreen.tsx b/ordering_site/src/pages/CheckoutScreen.tsx index 94434890..99aa52bf 100644 --- a/ordering_site/src/pages/CheckoutScreen.tsx +++ b/ordering_site/src/pages/CheckoutScreen.tsx @@ -336,52 +336,64 @@ const CheckoutScreen: React.FC = () => { -
-
- {paymentMethod === 'RAZORPAY' ? 'Amount payable' : 'Tokens to be deducted'} - - {paymentMethod === 'RAZORPAY' ? 'โ‚น' : '๐Ÿ…ก'}{totalPrice.toLocaleString()} - +
+
+
+ {paymentMethod === 'RAZORPAY' ? 'Amount payable' : 'Tokens to be deducted'} + + {paymentMethod === 'RAZORPAY' ? 'โ‚น' : '๐Ÿ…ก'}{totalPrice.toLocaleString()} + +
+

Inclusive of applicable item prices ยท No extra platform fee

+
+ + {statusMessage && ( + +
+ +
+
+

{statusMessage}

+
+
+ )} + + {isInsufficient && paymentMethod === 'RITZ_TOKEN' && ( + +
+ +
+ +
+
+
+
+ Short by ๐Ÿ…ก{(totalPrice - currentBalance).toLocaleString()} +
+

Top up tokens, or pay online with Razorpay instead.

+
+
+ )} + +
+
-

Inclusive of applicable item prices ยท No extra platform fee

- - {statusMessage && ( - -
- -
-
-

{statusMessage}

-
-
- )} - - {isInsufficient && paymentMethod === 'RITZ_TOKEN' && ( - -
- -
- -
-
-
-
- Short by ๐Ÿ…ก{(totalPrice - currentBalance).toLocaleString()} -
-

Top up tokens, or pay online with Razorpay instead.

-
-
- )}
diff --git a/ordering_site/src/pages/StallDetailScreen.css b/ordering_site/src/pages/StallDetailScreen.css index 6e8aab8e..89eec8df 100644 --- a/ordering_site/src/pages/StallDetailScreen.css +++ b/ordering_site/src/pages/StallDetailScreen.css @@ -7,16 +7,23 @@ position: relative; height: 220px; width: 100%; + z-index: 1 !important; } .detail-header.sticky { height: auto; padding: 12px 16px; background: var(--surface); - z-index: 100; + z-index: 100 !important; box-shadow: var(--shadow); } +.detail-content { + position: relative; + z-index: 50 !important; + margin-top: -40px !important; +} + .stall-detail-page .add-to-cart-container { position: absolute; bottom: -12px; @@ -77,13 +84,13 @@ } .stall-main-card { - margin: -40px 16px 20px; - background: var(--surface); + margin: 0 16px 20px; + background: var(--surface) !important; border-radius: 24px; - padding: 24px; + padding: 20px; position: relative; box-shadow: var(--shadow); - z-index: 5; + z-index: 100 !important; } .stall-header-info {