migrating vendor frontend to new architecture
This commit is contained in:
257
app/templates/vendor/login.html
vendored
257
app/templates/vendor/login.html
vendored
@@ -1,121 +1,164 @@
|
||||
{# app/templates/vendor/login.html #}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html :class="{ 'theme-dark': dark }" x-data="vendorLogin()" lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vendor Login - Multi-Tenant Ecommerce Platform</title>
|
||||
<link rel="stylesheet" href="/static/css/shared/base.css">
|
||||
<link rel="stylesheet" href="/static/css/shared/auth.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vendor Login - Multi-Tenant Platform</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='vendor/css/tailwind.output.css') }}" />
|
||||
<style>
|
||||
[x-cloak] { display: none !important; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="auth-page" x-data="vendorLogin()" x-init="init()" x-cloak>
|
||||
<div class="login-container">
|
||||
<!-- Vendor Info -->
|
||||
<template x-if="vendor">
|
||||
<div class="vendor-info" style="margin-bottom: 24px;">
|
||||
<h2 x-text="vendor.name" style="margin: 0; color: var(--primary-color);"></h2>
|
||||
<p class="text-muted" style="margin: 4px 0 0 0; font-size: var(--font-sm);">
|
||||
<strong x-text="vendor.vendor_code"></strong>
|
||||
</p>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
<div class="flex-1 h-full max-w-4xl mx-auto overflow-hidden bg-white rounded-lg shadow-xl dark:bg-gray-800">
|
||||
<div class="flex flex-col overflow-y-auto md:flex-row">
|
||||
<div class="h-32 md:h-auto md:w-1/2">
|
||||
<img aria-hidden="true" class="object-cover w-full h-full dark:hidden"
|
||||
src="{{ url_for('static', path='vendor/img/login-office.jpeg') }}" alt="Office" />
|
||||
<img aria-hidden="true" class="hidden object-cover w-full h-full dark:block"
|
||||
src="{{ url_for('static', path='vendor/img/login-office-dark.jpeg') }}" alt="Office" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="login-header">
|
||||
<div class="auth-logo">🏪</div>
|
||||
<h1>Vendor Portal</h1>
|
||||
<p>Sign in to manage your store</p>
|
||||
</div>
|
||||
|
||||
<!-- Alert Messages -->
|
||||
<div x-show="error"
|
||||
x-text="error"
|
||||
class="alert alert-error"
|
||||
x-transition></div>
|
||||
|
||||
<div x-show="success"
|
||||
x-text="success"
|
||||
class="alert alert-success"
|
||||
x-transition></div>
|
||||
|
||||
<!-- Login Form (only show if vendor found) -->
|
||||
<template x-if="vendor">
|
||||
<form @submit.prevent="handleLogin">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
x-model="credentials.username"
|
||||
:class="{ 'error': errors.username }"
|
||||
required
|
||||
autocomplete="username"
|
||||
placeholder="Enter your username"
|
||||
:disabled="loading"
|
||||
@input="clearErrors"
|
||||
>
|
||||
<div x-show="errors.username"
|
||||
x-text="errors.username"
|
||||
class="error-message show"
|
||||
x-transition></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
x-model="credentials.password"
|
||||
:class="{ 'error': errors.password }"
|
||||
required
|
||||
autocomplete="current-password"
|
||||
placeholder="Enter your password"
|
||||
:disabled="loading"
|
||||
@input="clearErrors"
|
||||
>
|
||||
<div x-show="errors.password"
|
||||
x-text="errors.password"
|
||||
class="error-message show"
|
||||
x-transition></div>
|
||||
</div>
|
||||
|
||||
<button type="submit"
|
||||
class="btn-login"
|
||||
:disabled="loading">
|
||||
<template x-if="!loading">
|
||||
<span>Sign In</span>
|
||||
<div class="flex items-center justify-center p-6 sm:p-12 md:w-1/2">
|
||||
<div class="w-full">
|
||||
<!-- Vendor Info -->
|
||||
<template x-if="vendor">
|
||||
<div class="mb-6 text-center">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 mb-4 rounded-full bg-purple-100 dark:bg-purple-600">
|
||||
<span class="text-2xl font-bold text-purple-600 dark:text-purple-100"
|
||||
x-text="vendor.name?.charAt(0).toUpperCase() || '🏪'"></span>
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold text-gray-700 dark:text-gray-200" x-text="vendor.name"></h2>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
<strong x-text="vendor.vendor_code"></strong>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="loading">
|
||||
<span>
|
||||
<span class="loading-spinner"></span>
|
||||
Signing in...
|
||||
</span>
|
||||
</template>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<!-- Vendor Not Found -->
|
||||
<template x-if="!vendor && !loading && checked">
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">🏪</div>
|
||||
<h3>Vendor Not Found</h3>
|
||||
<p>The vendor you're trying to access doesn't exist or is inactive.</p>
|
||||
<a href="/admin/login.html" class="btn btn-primary" style="margin-top: 16px;">
|
||||
Go to Admin Login
|
||||
</a>
|
||||
<h1 class="mb-4 text-xl font-semibold text-gray-700 dark:text-gray-200">
|
||||
Vendor Portal Login
|
||||
</h1>
|
||||
|
||||
<!-- Alert Messages -->
|
||||
<div x-show="error" x-text="error"
|
||||
class="px-4 py-3 mb-4 text-sm text-red-700 bg-red-100 rounded-lg dark:bg-red-200 dark:text-red-800"
|
||||
x-transition></div>
|
||||
|
||||
<div x-show="success" x-text="success"
|
||||
class="px-4 py-3 mb-4 text-sm text-green-700 bg-green-100 rounded-lg dark:bg-green-200 dark:text-green-800"
|
||||
x-transition></div>
|
||||
|
||||
<!-- Login Form (only show if vendor found) -->
|
||||
<template x-if="vendor">
|
||||
<form @submit.prevent="handleLogin">
|
||||
<label class="block text-sm">
|
||||
<span class="text-gray-700 dark:text-gray-400">Username</span>
|
||||
<input x-model="credentials.username"
|
||||
:disabled="loading"
|
||||
@input="clearErrors"
|
||||
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"
|
||||
:class="{ 'border-red-600': errors.username }"
|
||||
placeholder="Enter your username"
|
||||
autocomplete="username"
|
||||
required />
|
||||
<span x-show="errors.username" x-text="errors.username"
|
||||
class="text-xs text-red-600 dark:text-red-400"></span>
|
||||
</label>
|
||||
|
||||
<label class="block mt-4 text-sm">
|
||||
<span class="text-gray-700 dark:text-gray-400">Password</span>
|
||||
<input x-model="credentials.password"
|
||||
:disabled="loading"
|
||||
@input="clearErrors"
|
||||
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"
|
||||
:class="{ 'border-red-600': errors.password }"
|
||||
placeholder="***************"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
required />
|
||||
<span x-show="errors.password" x-text="errors.password"
|
||||
class="text-xs text-red-600 dark:text-red-400"></span>
|
||||
</label>
|
||||
|
||||
<button type="submit" :disabled="loading"
|
||||
class="block w-full px-4 py-2 mt-4 text-sm font-medium leading-5 text-center text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<span x-show="!loading">Log in</span>
|
||||
<span x-show="loading">
|
||||
<svg class="inline w-4 h-4 mr-2 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Signing in...
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<!-- Vendor Not Found -->
|
||||
<template x-if="!vendor && !loading && checked">
|
||||
<div class="text-center py-8">
|
||||
<div class="text-6xl mb-4">🏪</div>
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">
|
||||
Vendor Not Found
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||
The vendor you're trying to access doesn't exist or is inactive.
|
||||
</p>
|
||||
<a href="/" class="inline-flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple">
|
||||
Go to Platform Home
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div x-show="loading && !vendor" class="text-center py-8">
|
||||
<svg class="inline w-8 h-8 animate-spin text-purple-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">Loading vendor information...</p>
|
||||
</div>
|
||||
|
||||
<hr class="my-8" />
|
||||
|
||||
<p class="mt-4">
|
||||
<a class="text-sm font-medium text-purple-600 dark:text-purple-400 hover:underline"
|
||||
href="#">
|
||||
Forgot your password?
|
||||
</a>
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
<a class="text-sm font-medium text-gray-600 dark:text-gray-400 hover:underline"
|
||||
href="/">
|
||||
← Back to Platform
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div x-show="loading && !vendor" class="loading">
|
||||
<span class="loading-spinner loading-spinner-lg"></span>
|
||||
<p class="loading-text">Loading vendor information...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/shared/js/api-client.js"></script>
|
||||
<script src="/static/js/vendor/login.js"></script>
|
||||
<!-- Scripts - ORDER MATTERS! -->
|
||||
|
||||
<!-- 1. Log Configuration -->
|
||||
<script src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 2. Icons -->
|
||||
<script src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. Utils -->
|
||||
<script src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4. API Client -->
|
||||
<script src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 5. Alpine.js v3 -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.0/dist/cdn.min.js"></script>
|
||||
|
||||
<!-- 6. Login Logic -->
|
||||
<script src="{{ url_for('static', path='vendor/js/login.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user