Compare commits

...

10 commits

14 changed files with 4100 additions and 291 deletions

View file

@ -0,0 +1,76 @@
name: CI/CD Pipeline
on:
push:
pull_request:
deployment:
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Test
run: npm run test
- name: Build
run: npm run build
- name: Upload Build Artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy-beta:
needs: build-and-test
if: (github.event_name == 'push' && github.ref_name == 'beta') || (github.event_name == 'deployment' && github.event.deployment.environment == 'beta')
runs-on: ubuntu-latest
steps:
- name: Download Build Artifact
uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Deploy to Beta via FTP
env:
FTP_USERNAME: ${{ secrets.BETA_FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.BETA_FTP_PASSWORD }}
FTP_HOST: ${{ secrets.FTP_HOST }}
run: |
sudo apt-get update && sudo apt-get install -y lftp
lftp -d -u "$FTP_USERNAME","$FTP_PASSWORD" -e "set ssl:verify-certificate no; set ftp:ssl-allow yes; set ftp:ssl-force true; set ftp:ssl-protect-data true; set ftp:passive-mode true; mirror -R dist/ ./; quit" $FTP_HOST
deploy-prod:
needs: build-and-test
if: (github.event_name == 'push' && github.ref_name == 'main') || (github.event_name == 'deployment' && github.event.deployment.environment == 'production')
runs-on: ubuntu-latest
steps:
- name: Download Build Artifact
uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Deploy to Production via FTP
env:
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
FTP_HOST: ${{ secrets.FTP_HOST }}
run: |
sudo apt-get update && sudo apt-get install -y lftp
lftp -d -u "$FTP_USERNAME","$FTP_PASSWORD" -e "set ssl:verify-certificate no; set ftp:ssl-allow yes; set ftp:ssl-force true; set ftp:ssl-protect-data true; set ftp:passive-mode true; mirror -R dist/ ./; quit" $FTP_HOST

View file

@ -1,23 +0,0 @@
when:
- event: [push, pull_request]
steps:
- name: install
image: node:20-alpine
commands:
- npm ci
- name: lint
image: node:20-alpine
commands:
- npm run lint
- name: test
image: node:20-alpine
commands:
- npm run test
- name: build
image: node:20-alpine
commands:
- npm run build

View file

@ -1,32 +0,0 @@
when:
- event: deployment
environment: beta
steps:
- name: install
image: node:20-alpine
commands:
- npm ci
- name: test
image: node:20-alpine
commands:
- npm run test
- name: build
image: node:20-alpine
commands:
- npm run build
- name: deploy-beta
image: alpine:3.18
environment:
FTP_USERNAME:
from_secret: beta_ftp_username
FTP_PASSWORD:
from_secret: beta_ftp_password
FTP_HOST:
from_secret: ftp_host
commands:
- apk add --no-cache lftp
- lftp -d -u "$FTP_USERNAME","$FTP_PASSWORD" -e "set ssl:verify-certificate no; set ftp:ssl-allow yes; set ftp:ssl-force true; set ftp:ssl-protect-data true; set ftp:passive-mode true; mirror -R dist/ ./; quit" $FTP_HOST

View file

@ -1,32 +0,0 @@
when:
- event: deployment
environment: production
steps:
- name: install
image: node:20-alpine
commands:
- npm ci
- name: test
image: node:20-alpine
commands:
- npm run test
- name: build
image: node:20-alpine
commands:
- npm run build
- name: deploy-prod
image: alpine:3.18
environment:
FTP_USERNAME:
from_secret: ftp_username
FTP_PASSWORD:
from_secret: ftp_password
FTP_HOST:
from_secret: ftp_host
commands:
- apk add --no-cache lftp
- lftp -d -u "$FTP_USERNAME","$FTP_PASSWORD" -e "set ssl:verify-certificate no; set ftp:ssl-allow yes; set ftp:ssl-force true; set ftp:ssl-protect-data true; set ftp:passive-mode true; mirror -R dist/ ./; quit" $FTP_HOST

108
architecture_diagram.md Normal file
View file

@ -0,0 +1,108 @@
# Supplier Portal Architecture & Module Design
This document outlines the proposed module structure, page flows, and visual architecture for the E-Commerce Supplier Portal.
## 1. System Architecture & Modules
```mermaid
graph TD
%% Styling
classDef primary fill:#1A2B45,stroke:#1A2B45,color:#fff;
classDef accent fill:#E9C46A,stroke:#E9C46A,color:#1A2B45;
classDef container fill:#FFFFFF,stroke:#1A2B45,color:#1A2B45;
classDef bg fill:#F5F0EA,stroke:#1A2B45,color:#1A2B45;
%% Modules
AuthModule["Authentication Module"]:::primary
ProfileModule["Onboarding & Profile Module"]:::primary
ProductModule["Product Management"]:::primary
DashboardModule["Analytics & Dashboard"]:::primary
FulfillmentModule["Order & Fulfillment Tracking"]:::primary
WalletModule["Payout & Wallet"]:::primary
NotificationModule["Notification System"]:::primary
%% Components
Signup["Signup Page<br/>(Email, Phone, GSTIN Init)"]:::container
Login["Login Page<br/>(OTP / Password)"]:::container
ProfileComplete["Profile Completion Page<br/>(Store Info, Pickup Address, GSTIN Verify)"]:::container
ProdUpload["Single Upload / Modify Page"]:::container
BulkUpload["Bulk Excel/CSV Upload Page"]:::container
AnalyticsDash["Sales & Earnings Analytics<br/>(Yearly, Weekly, Daily, Custom Date Filters)"]:::container
StockReports["Stock & Inventory Tracking"]:::container
ReturnsDashboard["Customer Returns Center<br/>(Requests, Tracking & Quality Checks)"]:::container
PayoutCenter["Payout / Wallet Dashboard<br/>(Outstanding Balance, Withdrawal Request)"]:::container
ItemTracking["Item Tracking Dashboard<br/>(Individual Item Status, SKUs, Serials)"]:::container
TransitTracking["Transit Tracking Dashboard<br/>(Courier Status, Carrier Integration)"]:::container
%% Relations
AuthModule --> Signup
AuthModule --> Login
Signup --> ProfileComplete
ProfileComplete --> ProfileModule
ProductModule --> ProdUpload
ProductModule --> BulkUpload
DashboardModule --> AnalyticsDash
DashboardModule --> StockReports
FulfillmentModule --> ItemTracking
FulfillmentModule --> TransitTracking
FulfillmentModule --> ReturnsDashboard
WalletModule --> PayoutCenter
```
---
## 2. Detailed Page & Module Breakdown
### A. Authentication & Onboarding Module
1. **Signup Page**
- Business Email, Password, and Mobile Number validation.
- Initial GSTIN input (for verification).
2. **Login Page**
- Credentials or OTP-based secure login.
3. **Account Profile Completion Page (Onboarding Step 2)**
- **Store Details**: Upload Store Logo/Profile Image, Store Display Name.
- **Pickup & Shipping**: Pickup Address, contact person details.
- **Regulatory Info**: Verified GSTIN, Bank Account details (for payouts).
### B. Product & Inventory Management Module
1. **Single Product Upload & Modification**
- Form-based creation (Images, Title, Description, SKU, Category, Price, Stock count).
- Real-time preview of the product card matching our theme.
2. **Bulk Product Upload & Modify**
- Excel/CSV upload template download.
- Status log showing validation warnings (e.g., missing images, pricing errors).
### C. Analytical Dashboard Module
Provides comprehensive reporting with dynamic period filters (**Yearly, Weekly, Daily, and Custom Date Range**):
1. **Sales & Earnings Reports**
- Interactive charts showing Total Sales (Gross volume) vs. Total Earned (Net margin after commissions).
2. **Stock & Inventory Status**
- Low-stock alerts, active listings count, and inactive listings.
### D. Order & Fulfillment Tracking Module
1. **Item Tracking**
- Track individual items per order (SKU details, quantity, individual packaging status).
- Flag items: *Ready to Ship*, *Shipped*, *Delivered*, *Cancelled*.
2. **Transit Tracking**
- Real-time logistic carrier updates (e.g., DHL, FedEx, Local Post tracking number integration).
- Expected Delivery Date and transit milestones display.
3. **Return Tracking & Return Requests**
- **Items Requested for Return**: Lists customer return requests, reason for return, and custom images uploaded by the customer (e.g., defective product, wrong size). Action to *Approve* or *Reject* return.
- **In-Transit Return Tracking**: Real-time logistic progress of returning items from the customer back to the supplier hub.
### E. Wallet & Financials (Payout) Module
1. **Current Outstanding Balance**
- Live ready-to-withdraw funds display.
2. **Withdrawal Interface**
- Payout history list with status tracking (Pending, Approved, Transferred).
- "Withdraw Funds" action trigger.
### F. Notifications & Account Settings
1. **Header Notification Drawer**
- Real-time notices for new orders, low inventory, return requests, and completed payouts.
2. **Profile / Account Settings Page**
- Modify existing Store Profile Image, Pickup Location details, and GSTIN certificates.

86
guide.md Normal file
View file

@ -0,0 +1,86 @@
# Supplier Portal - View & Navigation Guide
This guide explains how to start the development server, navigate the screens, and view the onboarding flows and simulated dashboard preview.
## 1. Running the Portal Locally
To start the Vite development server, run the following command in the project root:
```bash
npm run dev
```
By default, the server runs at **[http://localhost:5173/](http://localhost:5173/)** (or the port specified in your console).
---
## 2. Page Routing & State Mapping
The portal uses a client-side state router mapping component views to logical routes:
| Route State | Component/View Description | Navigable Via |
| :--- | :--- | :--- |
| `home` | **Landing Page**: Brand value proposition, hero banner, primary action CTAs. | Logo click, "Platform" header link. |
| `about` | **About Us**: Organization mission details and team profiles. | "Success Stories" header link. |
| `contact` | **Contact Support**: "Get in Touch" inquiry form and help desk coordinates. | "Support" header link. |
| `login` | **Supplier Login**: Account login via password credentials or OTP mock. | "Login" header button. |
| `signup` | **Supplier Registration**: Fields for business email, password, and GSTIN. | "Get Started" header button. |
| `profile-completion` | **Profile Wizard (Step 2)**: Logo picker, bio, and interactive GSTIN validation. | Auto-redirect on Signup form submit. |
| `confirmation` | **Dashboard Preview (Step 3)**: Payout status notifications and mock graphs. | Auto-redirect on Profile Completion save. |
| `dashboard` | **Seller Dashboard & Tools**: Overview performance metrics, single/bulk product uploads, orders tracking log, returns approvals, wallet payouts, and settings configuration. | Click "Go to Dashboard" button in confirmation, or submit Login form. |
--- te
## 3. Navigating the Phase 1 Onboarding Flow
You can step through the interactive onboarding flow sequentially to experience the full walkthrough:
### Step A: The Landing Page
- Open the application. You will see the **Global Artisans Hub** landing page with the primary theme (Deep Navy Blue headers/footers, Amber Gold accents, and Warm Cream backgrounds).
- Click **Platform**, **Success Stories** (About Us), or **Support** (Contact Us) in the header navigation to view the respective information layouts.
### Step B: Account Registration
1. Click **Get Started** in the header.
2. The view will switch to the **Register** tab.
3. Fill in the required fields:
- **Business Email**
- **Mobile Number**
- **Create Password**
- **GSTIN / Tax ID**
4. Click **Register Business**.
### Step C: Profile Completion (Step 2 of 3)
1. You will be taken to the **Complete Your Supplier Profile** wizard.
2. Enter a **Store Display Name**.
3. (Optional) Choose an image file to upload. It will immediately show an avatar logo preview.
4. Enter an **About Your Craft / Business** description.
5. Fill in the **Business Address for Pickup** fields (Street Address, City, State, Pincode).
6. Enter a GSTIN, and click **Verify GSTIN**. The button will show a loading spinner, then update to **Verified ✓** status.
7. Click **Save & Continue**.
### Step D: Onboarding Confirmation (Step 3 of 3)
- You will arrive at the **Welcome to Global Artisans Hub!** confirmation view.
- Click **Go to Dashboard (Preview Only)** to go to the live seller portal dashboard page.
- Alternatively, you can directly access the dashboard page by going to **Login** -> enter credentials -> click **Secure Login**.
### Step E: Navigating the Seller Dashboard & Tools
Once inside the active dashboard (`/dashboard`), use the left sidebar menu to navigate the tools:
1. **Overview & Analytics**: View Sales, net margins, stock, and returns. Toggle the date filters (Year, Week, Day, Custom Date) to see the metrics update dynamically.
2. **Manage Products**:
- View your active inventory listing.
- Fill out the **Upload Product** form on the right to add a product or click **Edit** on a row to modify it.
- Click the bulk upload zone to simulate importing products via CSV files.
3. **Orders & Transit**: Track active orders, status (Ready to Ship, Shipped, Delivered), carriers, and tracking coordinates.
4. **Returns Management**: View buyer return requests. Click **Approve** or **Reject** to update their logistics status in the warehouse transit log.
5. **Wallet & Payouts**: Enter an amount to process a withdrawal from your outstanding ready balance.
6. **Store Settings**: Update your store name, logo file, bio, and pickup coordinates.
---
## 4. Run Automated Component Tests
To run the Vitest unit tests verifying these navigation flows and tools, execute:
```bash
npm run test
```

1198
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "oxlint",
"test": "echo 'No tests specified' && exit 0",
"test": "vitest run",
"preview": "vite preview"
},
"dependencies": {
@ -15,12 +15,17 @@
"react-dom": "^19.2.8"
},
"devDependencies": {
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^7.0.0",
"@testing-library/react": "^16.3.2",
"@types/node": "^24.13.3",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.4",
"jsdom": "^30.0.1",
"oxlint": "^1.75.0",
"typescript": "~6.0.2",
"vite": "^8.2.0"
"vite": "^8.2.0",
"vitest": "^4.1.10"
}
}

133
src/App.test.tsx Normal file
View file

@ -0,0 +1,133 @@
import { render, screen, fireEvent } from '@testing-library/react'
import { describe, it, expect, vi, beforeAll } from 'vitest'
import App from './App'
// Mock window.scrollTo since jsdom does not implement it
beforeAll(() => {
window.scrollTo = vi.fn()
})
describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
it('renders landing page with correct primary titles', () => {
render(<App />)
expect(screen.getByText(/Sell Globally\./i)).toBeInTheDocument()
expect(screen.getByText(/Celebrate Craft\./i)).toBeInTheDocument()
expect(screen.getByRole('heading', { name: /^Expand Your Reach$/i })).toBeInTheDocument()
})
it('navigates to Support page and handles contact form submission', () => {
render(<App />)
const supportBtn = screen.getByText('Support')
fireEvent.click(supportBtn)
const nameInput = screen.getByLabelText(/Full Name \*/i)
const emailInput = screen.getByLabelText(/Email Address \*/i)
const msgInput = screen.getByLabelText(/Message \*/i)
fireEvent.change(nameInput, { target: { value: 'John Doe' } })
fireEvent.change(emailInput, { target: { value: 'john@example.com' } })
fireEvent.change(msgInput, { target: { value: 'Hello support!' } })
const alertMock = vi.spyOn(window, 'alert').mockImplementation(() => {})
const submitBtn = screen.getByText('Submit Inquiry')
fireEvent.click(submitBtn)
expect(alertMock).toHaveBeenCalled()
alertMock.mockRestore()
})
it('signs up successfully and completes profile to active dashboard', async () => {
render(<App />)
const getStartedBtn = screen.getByRole('button', { name: /^Get Started$/i })
fireEvent.click(getStartedBtn)
const emailInput = screen.getByLabelText(/Business Email \*/i)
const phoneInput = screen.getByLabelText(/Mobile Number \*/i)
const passInput = screen.getByLabelText(/Create Password \*/i)
const taxInput = screen.getByLabelText(/GSTIN \/ Tax ID \*/i)
fireEvent.change(emailInput, { target: { value: 'seller@example.com' } })
fireEvent.change(phoneInput, { target: { value: '9876543210' } })
fireEvent.change(passInput, { target: { value: 'password123' } })
fireEvent.change(taxInput, { target: { value: '29AAAAA1111A1Z1' } })
const registerBtn = screen.getByRole('button', { name: /Register Business/i })
fireEvent.click(registerBtn)
expect(screen.getByText('Step 2 of 3: Business Details')).toBeInTheDocument()
const storeNameInput = screen.getByLabelText(/Store Display Name \*/i)
fireEvent.change(storeNameInput, { target: { value: 'Crafty Store' } })
const bioText = screen.getByLabelText(/About Your Craft \/ Business \*/i)
fireEvent.change(bioText, { target: { value: 'Handmade pottery.' } })
const streetInput = screen.getByPlaceholderText('Street Address')
const cityInput = screen.getByPlaceholderText('City')
const stateInput = screen.getByPlaceholderText('State')
const pincodeInput = screen.getByPlaceholderText('Pincode')
fireEvent.change(streetInput, { target: { value: '123 Loom Lane' } })
fireEvent.change(cityInput, { target: { value: 'Handloom City' } })
fireEvent.change(stateInput, { target: { value: 'Karnataka' } })
fireEvent.change(pincodeInput, { target: { value: '560001' } })
const saveBtn = screen.getByRole('button', { name: /Save & Continue/i })
fireEvent.click(saveBtn)
// Redirects directly to Dashboard Page
expect(screen.getByText('Performance Analytics')).toBeInTheDocument()
expect(screen.getByText(/Total Sales Volume/i)).toBeInTheDocument()
})
it('logs in successfully and navigates dashboard tools', () => {
render(<App />)
const loginBtn = screen.getByRole('button', { name: /^Login$/i })
fireEvent.click(loginBtn)
const emailInput = screen.getByLabelText(/Business Email/i)
const passInput = screen.getByLabelText(/Password/i)
fireEvent.change(emailInput, { target: { value: 'seller@example.com' } })
fireEvent.change(passInput, { target: { value: 'password123' } })
const submitBtn = screen.getByRole('button', { name: /Secure Login/i })
fireEvent.click(submitBtn)
// Check dashboard rendering
expect(screen.getByText('Performance Analytics')).toBeInTheDocument()
// Check Sidebar Tab click: Manage Products
const productsTabBtn = screen.getByText(/Manage Products/i)
fireEvent.click(productsTabBtn)
expect(screen.getByText(/Active Inventory/i)).toBeInTheDocument()
expect(screen.getByText(/Upload New Product/i)).toBeInTheDocument()
// Check Sidebar Tab click: Orders & Transit
const ordersTabBtn = screen.getByText(/Orders & Transit/i)
fireEvent.click(ordersTabBtn)
expect(screen.getByText(/Active Orders & Payout status/i)).toBeInTheDocument()
// Check Sidebar Tab click: Returns Management
const returnsTabBtn = screen.getByText(/Returns Management/i)
fireEvent.click(returnsTabBtn)
expect(screen.getByText(/Returns & Quality Assurance Center/i)).toBeInTheDocument()
expect(screen.getByText(/Items Requested for Return/i)).toBeInTheDocument()
// Check Sidebar Tab click: Wallet & Payouts
const walletTabBtn = screen.getByText(/Wallet & Payouts/i)
fireEvent.click(walletTabBtn)
expect(screen.getByText(/Wallet & Payout Portal/i)).toBeInTheDocument()
expect(screen.getByText(/Outstanding Ready Balance/i)).toBeInTheDocument()
})
})

File diff suppressed because it is too large Load diff

116
src/config.ts Normal file
View file

@ -0,0 +1,116 @@
export const CONFIG = {
companyName: 'Global Artisans Hub',
logoLetter: 'A',
supportEmail: 'support@globalartisanshub.com',
supportPhone: '+1 (800) 555-0199',
address: '1775 Artisan Ridge Rd, Craftsville, CA 90210',
hero: {
title: 'Sell Globally. Celebrate Craft.',
subtitle: 'Join the premier marketplace for artisans and reach millions of conscious customers worldwide.',
image: 'https://images.unsplash.com/photo-1513519245088-0e12902e5a38?auto=format&fit=crop&q=80&w=800'
},
features: [
{
icon: '🌍',
title: 'Expand Your Reach',
description: 'Globalize your marketplace for artisans and reach millions of conscious customers.'
},
{
icon: '🛠️',
title: 'Easy Inventory Tools',
description: 'Dashboard marketplace to manage and update listings with ease.'
},
{
icon: '🛡️',
title: 'Secure Payments',
description: 'Secure payments and reliable payout processing directly to your bank account.'
}
],
featuredArtisan: {
name: 'Naomi K.',
role: 'Master Weaver',
quote: '"Joining the Global Artisans Hub has transformed our community. We went from selling at local weekend fairs to serving buyers worldwide, preserving our traditional craft."',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&q=80&w=300'
},
about: {
missionTitle: 'Our Mission',
missionDescription: 'We aim to empower artisan communities worldwide, providing a premium, transparent, and direct channel to conscious consumers globally.',
team: [
{
name: 'Sunder R.',
role: 'Founder & CEO',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&q=80&w=150'
},
{
name: 'Sarayu N.',
role: 'Head of Artisan Partnerships',
avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&q=80&w=150'
},
{
name: 'John C.',
role: 'Operations Lead',
avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&q=80&w=150'
},
{
name: 'Elena P.',
role: 'Tech Lead',
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&q=80&w=150'
}
]
},
// --- Mock Dashboard Data ---
dashboardData: {
filters: {
year: {
totalSales: 45280.00,
totalEarned: 38488.00,
stockDetails: 342,
returnedItems: 12,
chartValues: [30, 45, 35, 60, 75, 55, 80, 65, 90, 70, 85, 95] // Monthly values
},
week: {
totalSales: 1240.00,
totalEarned: 1054.00,
stockDetails: 342,
returnedItems: 1,
chartValues: [40, 60, 50, 70, 45, 80, 90] // Daily values
},
day: {
totalSales: 210.00,
totalEarned: 178.50,
stockDetails: 342,
returnedItems: 0,
chartValues: [10, 15, 20, 25, 35, 45, 30, 20, 10] // Hourly intervals
},
custom: {
totalSales: 5820.00,
totalEarned: 4947.00,
stockDetails: 342,
returnedItems: 3,
chartValues: [50, 40, 65, 55, 75, 85, 60, 70] // Range intervals
}
},
initialProducts: [
{ id: '1', title: 'Handwoven Indigo Shawl', category: 'Apparel', price: 85.00, stock: 45, sku: 'SHAWL-IND-01', image: 'https://images.unsplash.com/photo-1544022613-e87ca75a784a?auto=format&fit=crop&q=80&w=100' },
{ id: '2', title: 'Terracotta Clay Pot Set', category: 'Home Decor', price: 42.00, stock: 24, sku: 'POT-TER-02', image: 'https://images.unsplash.com/photo-1612196808214-b8e1d6145a8c?auto=format&fit=crop&q=80&w=100' },
{ id: '3', title: 'Brass Elephant Figurine', category: 'Sculptures', price: 120.00, stock: 12, sku: 'FIG-ELE-03', image: 'https://images.unsplash.com/photo-1590736969955-71cc94801759?auto=format&fit=crop&q=80&w=100' }
],
initialOrders: [
{ id: 'ORD-8492', date: '2026-08-07', item: 'Handwoven Indigo Shawl', quantity: 1, customer: 'Alice Vance', total: 85.00, status: 'Ready to Ship', carrier: 'DHL Express', tracking: 'DHL-9284102', eta: '2026-08-10' },
{ id: 'ORD-8488', date: '2026-08-06', item: 'Terracotta Clay Pot Set', quantity: 2, customer: 'David Miller', total: 84.00, status: 'Shipped', carrier: 'FedEx Ground', tracking: 'FDX-5829104', eta: '2026-08-09' },
{ id: 'ORD-8471', date: '2026-08-05', item: 'Brass Elephant Figurine', quantity: 1, customer: 'Sarah Connor', total: 120.00, status: 'Delivered', carrier: 'Local Express', tracking: 'LOC-1294801', eta: '2026-08-07' }
],
initialReturns: [
{ id: 'RET-019', orderId: 'ORD-8411', customer: 'Lillian G.', item: 'Handwoven Indigo Shawl', reason: 'Slightly different shade than pictured', status: 'Pending Approval', image: 'https://images.unsplash.com/photo-1544022613-e87ca75a784a?auto=format&fit=crop&q=80&w=100', returningTracking: 'DHL-RET-9031' },
{ id: 'RET-018', orderId: 'ORD-8390', customer: 'Robert H.', item: 'Terracotta Clay Pot Set', reason: 'Damaged in transit', status: 'In Transit', image: 'https://images.unsplash.com/photo-1612196808214-b8e1d6145a8c?auto=format&fit=crop&q=80&w=100', returningTracking: 'FDX-RET-2940' }
]
}
}

File diff suppressed because it is too large Load diff

1
src/setupTests.ts Normal file
View file

@ -0,0 +1 @@
import '@testing-library/jest-dom'

13
vitest.config.ts Normal file
View file

@ -0,0 +1,13 @@
import { defineConfig, mergeConfig } from 'vitest/config'
import viteConfig from './vite.config.ts'
export default mergeConfig(
viteConfig,
defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.ts',
},
})
)