adding beta stage implementation
This commit is contained in:
parent
d45ae569d1
commit
b54a897b88
4 changed files with 157 additions and 12 deletions
80
cypress/e2e/api.cy.ts
Normal file
80
cypress/e2e/api.cy.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
describe('Seller Central Django Backend API E2E Tests', () => {
|
||||||
|
const backendUrl = 'http://localhost:8000/api';
|
||||||
|
|
||||||
|
it('verifies product list', () => {
|
||||||
|
cy.request({
|
||||||
|
method: 'GET',
|
||||||
|
url: `${backendUrl}/products/`
|
||||||
|
}).then((response) => {
|
||||||
|
expect(response.status).to.eq(200);
|
||||||
|
expect(response.body).to.be.an('array');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates and deletes a product', () => {
|
||||||
|
const testSku = `CY-SKU-${Date.now()}`;
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${backendUrl}/products/`,
|
||||||
|
body: {
|
||||||
|
title: 'Cypress Test Pot',
|
||||||
|
category: 'Home Decor',
|
||||||
|
price: '45.00',
|
||||||
|
stock: 5,
|
||||||
|
sku: testSku
|
||||||
|
}
|
||||||
|
}).then((response) => {
|
||||||
|
expect(response.status).to.eq(201);
|
||||||
|
expect(response.body.sku).to.eq(testSku);
|
||||||
|
const productId = response.body.id;
|
||||||
|
|
||||||
|
// Delete the product
|
||||||
|
cy.request({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: `${backendUrl}/products/${productId}/`
|
||||||
|
}).then((delResponse) => {
|
||||||
|
expect(delResponse.status).to.eq(204);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies order list and acceptance', () => {
|
||||||
|
cy.request({
|
||||||
|
method: 'GET',
|
||||||
|
url: `${backendUrl}/orders/`
|
||||||
|
}).then((response) => {
|
||||||
|
expect(response.status).to.eq(200);
|
||||||
|
expect(response.body).to.be.an('array');
|
||||||
|
const order = response.body.find((o: any) => o.status === 'Pending Acceptance');
|
||||||
|
if (order) {
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${backendUrl}/orders/${order.id}/accept/`
|
||||||
|
}).then((acceptResponse) => {
|
||||||
|
expect(acceptResponse.status).to.eq(200);
|
||||||
|
expect(acceptResponse.body.status).to.eq('Ready to Ship');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies wallet summary and payout withdrawal', () => {
|
||||||
|
cy.request({
|
||||||
|
method: 'GET',
|
||||||
|
url: `${backendUrl}/wallet/`
|
||||||
|
}).then((response) => {
|
||||||
|
expect(response.status).to.eq(200);
|
||||||
|
const initialOutstanding = parseFloat(response.body.outstanding);
|
||||||
|
if (initialOutstanding > 10) {
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${backendUrl}/wallet/withdraw/`,
|
||||||
|
body: { amount: '10.00' }
|
||||||
|
}).then((withdrawResponse) => {
|
||||||
|
expect(withdrawResponse.status).to.eq(200);
|
||||||
|
expect(parseFloat(withdrawResponse.body.outstanding)).to.eq(initialOutstanding - 10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { render, screen, fireEvent } from '@testing-library/react'
|
import { render, screen, fireEvent } from '@testing-library/react'
|
||||||
import { describe, it, expect, vi, beforeAll } from 'vitest'
|
import { describe, it, expect, vi, beforeAll, beforeEach } from 'vitest'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
||||||
// Mock window.scrollTo since jsdom does not implement it
|
// Mock window.scrollTo since jsdom does not implement it
|
||||||
|
|
@ -7,6 +7,10 @@ beforeAll(() => {
|
||||||
window.scrollTo = vi.fn()
|
window.scrollTo = vi.fn()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
})
|
||||||
|
|
||||||
describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
|
describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
|
||||||
it('renders landing page with correct primary titles', () => {
|
it('renders landing page with correct primary titles', () => {
|
||||||
render(<App />)
|
render(<App />)
|
||||||
|
|
|
||||||
75
src/App.tsx
75
src/App.tsx
|
|
@ -40,16 +40,41 @@ interface ReturnRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [currentPage, setCurrentPage] = useState<Page>('home')
|
const [currentPage, setCurrentPage] = useState<Page>(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return (localStorage.getItem('seller_page') as Page) || 'home'
|
||||||
|
}
|
||||||
|
return 'home'
|
||||||
|
})
|
||||||
const [activeTab, setActiveTab] = useState<'login' | 'register'>('login')
|
const [activeTab, setActiveTab] = useState<'login' | 'register'>('login')
|
||||||
|
|
||||||
// Onboarding Status
|
// Onboarding Status
|
||||||
const [isProfileComplete, setIsProfileComplete] = useState(false)
|
const [isProfileComplete, setIsProfileComplete] = useState<boolean>(() => {
|
||||||
const [profileStep, setProfileStep] = useState(1)
|
if (typeof window !== 'undefined') {
|
||||||
|
return localStorage.getItem('seller_is_profile_complete') === 'true'
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
const [profileStep, setProfileStep] = useState<number>(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return Number(localStorage.getItem('seller_profile_step')) || 1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
})
|
||||||
|
|
||||||
// Registration / Onboarding Form States
|
// Registration / Onboarding Form States
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState(() => {
|
||||||
const [phone, setPhone] = useState('')
|
if (typeof window !== 'undefined') {
|
||||||
|
return localStorage.getItem('seller_email') || ''
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
const [phone, setPhone] = useState(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return localStorage.getItem('seller_phone') || ''
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
|
|
||||||
// Step 1: Verification
|
// Step 1: Verification
|
||||||
|
|
@ -67,7 +92,12 @@ export default function App() {
|
||||||
const [panFile, setPanFile] = useState<string | null>(null)
|
const [panFile, setPanFile] = useState<string | null>(null)
|
||||||
|
|
||||||
// Step 3: Store and Location details
|
// Step 3: Store and Location details
|
||||||
const [storeName, setStoreName] = useState('My Artisan Handloom')
|
const [storeName, setStoreName] = useState(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return localStorage.getItem('seller_store_name') || 'My Artisan Handloom'
|
||||||
|
}
|
||||||
|
return 'My Artisan Handloom'
|
||||||
|
})
|
||||||
const [storeLogo, setStoreLogo] = useState<string | null>(null)
|
const [storeLogo, setStoreLogo] = useState<string | null>(null)
|
||||||
const [businessBio, setBusinessBio] = useState('Traditional weaving and local sustainable designs.')
|
const [businessBio, setBusinessBio] = useState('Traditional weaving and local sustainable designs.')
|
||||||
const [address, setAddress] = useState({
|
const [address, setAddress] = useState({
|
||||||
|
|
@ -159,32 +189,55 @@ export default function App() {
|
||||||
const publicPages: Page[] = ['home', 'about', 'contact', 'login', 'signup', 'forgot-password', 'login-otp']
|
const publicPages: Page[] = ['home', 'about', 'contact', 'login', 'signup', 'forgot-password', 'login-otp']
|
||||||
const complete = isProfileComplete || forceComplete
|
const complete = isProfileComplete || forceComplete
|
||||||
|
|
||||||
|
let target = page
|
||||||
if (!complete && !publicPages.includes(page) && page !== 'profile-completion') {
|
if (!complete && !publicPages.includes(page) && page !== 'profile-completion') {
|
||||||
alert('Access Denied: Please complete your supplier profile first!')
|
alert('Access Denied: Please complete your supplier profile first!')
|
||||||
setCurrentPage('profile-completion')
|
target = 'profile-completion'
|
||||||
} else {
|
|
||||||
setCurrentPage(page)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setCurrentPage(target)
|
||||||
|
localStorage.setItem('seller_page', target)
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
localStorage.clear()
|
||||||
|
setIsProfileComplete(false)
|
||||||
|
setProfileStep(1)
|
||||||
|
setEmail('')
|
||||||
|
setPhone('')
|
||||||
|
setPassword('')
|
||||||
|
setStoreName('My Artisan Handloom')
|
||||||
|
navigateTo('home')
|
||||||
|
}
|
||||||
|
|
||||||
const handleRegisterSubmit = (e: React.FormEvent) => {
|
const handleRegisterSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
localStorage.setItem('seller_email', email)
|
||||||
|
localStorage.setItem('seller_phone', phone)
|
||||||
navigateTo('profile-completion')
|
navigateTo('profile-completion')
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleLoginSubmit = (e: React.FormEvent) => {
|
const handleLoginSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setIsProfileComplete(true)
|
setIsProfileComplete(true)
|
||||||
|
localStorage.setItem('seller_is_profile_complete', 'true')
|
||||||
|
localStorage.setItem('seller_email', email)
|
||||||
navigateTo('dashboard', true)
|
navigateTo('dashboard', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleProfileSubmit = (e: React.FormEvent) => {
|
const handleProfileSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (profileStep < 3) {
|
if (profileStep < 3) {
|
||||||
setProfileStep(prev => prev + 1)
|
const nextStep = profileStep + 1
|
||||||
|
setProfileStep(nextStep)
|
||||||
|
localStorage.setItem('seller_profile_step', String(nextStep))
|
||||||
} else {
|
} else {
|
||||||
setIsProfileComplete(true)
|
setIsProfileComplete(true)
|
||||||
|
localStorage.setItem('seller_is_profile_complete', 'true')
|
||||||
|
localStorage.setItem('seller_store_name', storeName)
|
||||||
|
localStorage.setItem('seller_phone', phone)
|
||||||
|
localStorage.setItem('seller_email', email)
|
||||||
navigateTo('welcome-tour', true)
|
navigateTo('welcome-tour', true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +381,7 @@ export default function App() {
|
||||||
</nav>
|
</nav>
|
||||||
<div className="nav-buttons">
|
<div className="nav-buttons">
|
||||||
{currentPage === 'dashboard' ? (
|
{currentPage === 'dashboard' ? (
|
||||||
<button className="btn btn-secondary" onClick={() => navigateTo('home')}>
|
<button className="btn btn-secondary" onClick={handleLogout}>
|
||||||
Logout
|
Logout
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
|
const getApiBaseUrl = () => {
|
||||||
|
if (typeof window !== 'undefined' && window.location.hostname === 'betasuppliers.tipro.in') {
|
||||||
|
return 'http://16.113.57.127:8000';
|
||||||
|
}
|
||||||
|
return 'http://localhost:8000';
|
||||||
|
};
|
||||||
|
|
||||||
export const CONFIG = {
|
export const CONFIG = {
|
||||||
|
apiBaseUrl: getApiBaseUrl(),
|
||||||
companyName: 'Global Artisans Hub',
|
companyName: 'Global Artisans Hub',
|
||||||
logoLetter: 'A',
|
logoLetter: 'A',
|
||||||
supportEmail: 'support@globalartisanshub.com',
|
supportEmail: 'support@globalartisanshub.com',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue