Phase 1 - Sidebar Refactor: - Refactor sidebar to use collapsible sections with Alpine.js - Add localStorage persistence for section states - Reorganize navigation into logical groups Phase 2 - Core JS Files: - Add products.js: product CRUD, search, filtering, toggle active/featured - Add orders.js: order list, status management, filtering - Add inventory.js: stock tracking, adjust/set quantity modals - Add customers.js: customer list, order history, messaging - Add team.js: member invite, role management, remove members - Add profile.js: profile editing with form validation - Add settings.js: tabbed settings (general, marketplace, notifications) Templates updated from placeholders to full functional UIs. Vendor frontend now at ~90% parity with admin. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
259 lines
17 KiB
HTML
259 lines
17 KiB
HTML
{# app/templates/vendor/settings.html #}
|
|
{% extends "vendor/base.html" %}
|
|
{% from 'shared/macros/headers.html' import page_header_flex %}
|
|
{% from 'shared/macros/alerts.html' import loading_state, error_state %}
|
|
|
|
{% block title %}Settings{% endblock %}
|
|
|
|
{% block alpine_data %}vendorSettings(){% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Page Header -->
|
|
{% call page_header_flex(title='Settings', subtitle='Configure your vendor preferences') %}
|
|
{% endcall %}
|
|
|
|
{{ loading_state('Loading settings...') }}
|
|
|
|
{{ error_state('Error loading settings') }}
|
|
|
|
<!-- Settings Content -->
|
|
<div x-show="!loading && !error" class="w-full mb-8">
|
|
<div class="flex flex-col md:flex-row gap-6">
|
|
<!-- Settings Navigation -->
|
|
<div class="w-full md:w-64 flex-shrink-0">
|
|
<div class="bg-white rounded-lg shadow-xs dark:bg-gray-800 p-2">
|
|
<template x-for="section in sections" :key="section.id">
|
|
<button
|
|
@click="setSection(section.id)"
|
|
:class="{
|
|
'w-full flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-colors': true,
|
|
'text-purple-600 bg-purple-50 dark:bg-purple-900/20 dark:text-purple-400': activeSection === section.id,
|
|
'text-gray-600 hover:bg-gray-50 dark:text-gray-400 dark:hover:bg-gray-700': activeSection !== section.id
|
|
}"
|
|
>
|
|
<span x-html="$icon(section.icon, 'w-5 h-5 mr-3')"></span>
|
|
<span x-text="section.label"></span>
|
|
</button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Panels -->
|
|
<div class="flex-1">
|
|
<!-- General Settings -->
|
|
<div x-show="activeSection === 'general'" class="bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
|
<div class="p-4 border-b dark:border-gray-700">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200">General Settings</h3>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Basic vendor configuration</p>
|
|
</div>
|
|
<div class="p-4">
|
|
<div class="space-y-6">
|
|
<!-- Subdomain -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Subdomain
|
|
</label>
|
|
<div class="flex items-center">
|
|
<input
|
|
type="text"
|
|
x-model="generalForm.subdomain"
|
|
disabled
|
|
class="flex-1 px-4 py-2 text-sm text-gray-500 bg-gray-100 border border-gray-200 rounded-l-lg dark:text-gray-400 dark:bg-gray-700 dark:border-gray-600"
|
|
/>
|
|
<span class="px-4 py-2 text-sm text-gray-500 bg-gray-50 border border-l-0 border-gray-200 rounded-r-lg dark:text-gray-400 dark:bg-gray-600 dark:border-gray-600">
|
|
.yourplatform.com
|
|
</span>
|
|
</div>
|
|
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Contact support to change your subdomain</p>
|
|
</div>
|
|
|
|
<!-- Active Status -->
|
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
<div>
|
|
<p class="font-medium text-gray-700 dark:text-gray-300">Store Status</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Your store is currently visible to customers</p>
|
|
</div>
|
|
<span
|
|
:class="settings?.is_active
|
|
? 'px-3 py-1 text-sm font-semibold text-green-700 bg-green-100 rounded-full dark:bg-green-700 dark:text-green-100'
|
|
: 'px-3 py-1 text-sm font-semibold text-gray-700 bg-gray-200 rounded-full dark:bg-gray-600 dark:text-gray-100'"
|
|
x-text="settings?.is_active ? 'Active' : 'Inactive'"
|
|
></span>
|
|
</div>
|
|
|
|
<!-- Verification Status -->
|
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
<div>
|
|
<p class="font-medium text-gray-700 dark:text-gray-300">Verification Status</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Verified vendors get a badge on their store</p>
|
|
</div>
|
|
<span
|
|
:class="settings?.is_verified
|
|
? 'px-3 py-1 text-sm font-semibold text-blue-700 bg-blue-100 rounded-full dark:bg-blue-700 dark:text-blue-100'
|
|
: 'px-3 py-1 text-sm font-semibold text-gray-700 bg-gray-200 rounded-full dark:bg-gray-600 dark:text-gray-100'"
|
|
x-text="settings?.is_verified ? 'Verified' : 'Not Verified'"
|
|
></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Marketplace Settings -->
|
|
<div x-show="activeSection === 'marketplace'" class="bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
|
<div class="p-4 border-b dark:border-gray-700">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200">Marketplace Integration</h3>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Configure external marketplace feeds</p>
|
|
</div>
|
|
<div class="p-4">
|
|
<div class="space-y-6">
|
|
<!-- Letzshop CSV URLs -->
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
<h4 class="font-medium text-gray-700 dark:text-gray-300 mb-4">Letzshop CSV Feed URLs</h4>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">
|
|
Enter the URLs for your Letzshop product feeds in different languages.
|
|
</p>
|
|
|
|
<!-- French URL -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
French (FR)
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
type="url"
|
|
x-model="marketplaceForm.letzshop_csv_url_fr"
|
|
@input="markChanged()"
|
|
class="flex-1 px-4 py-2 text-sm text-gray-700 bg-white border border-gray-200 rounded-lg dark:text-gray-300 dark:bg-gray-800 dark:border-gray-600 focus:border-purple-400 focus:outline-none focus:ring-1 focus:ring-purple-400"
|
|
placeholder="https://..."
|
|
/>
|
|
<button
|
|
@click="testLetzshopUrl('fr')"
|
|
:disabled="saving"
|
|
class="px-3 py-2 text-sm text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
|
|
>
|
|
Test
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- English URL -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
English (EN)
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
type="url"
|
|
x-model="marketplaceForm.letzshop_csv_url_en"
|
|
@input="markChanged()"
|
|
class="flex-1 px-4 py-2 text-sm text-gray-700 bg-white border border-gray-200 rounded-lg dark:text-gray-300 dark:bg-gray-800 dark:border-gray-600 focus:border-purple-400 focus:outline-none focus:ring-1 focus:ring-purple-400"
|
|
placeholder="https://..."
|
|
/>
|
|
<button
|
|
@click="testLetzshopUrl('en')"
|
|
:disabled="saving"
|
|
class="px-3 py-2 text-sm text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
|
|
>
|
|
Test
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- German URL -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
German (DE)
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
type="url"
|
|
x-model="marketplaceForm.letzshop_csv_url_de"
|
|
@input="markChanged()"
|
|
class="flex-1 px-4 py-2 text-sm text-gray-700 bg-white border border-gray-200 rounded-lg dark:text-gray-300 dark:bg-gray-800 dark:border-gray-600 focus:border-purple-400 focus:outline-none focus:ring-1 focus:ring-purple-400"
|
|
placeholder="https://..."
|
|
/>
|
|
<button
|
|
@click="testLetzshopUrl('de')"
|
|
:disabled="saving"
|
|
class="px-3 py-2 text-sm text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 dark:text-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500"
|
|
>
|
|
Test
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Save Button -->
|
|
<div class="flex justify-end mt-4 pt-4 border-t dark:border-gray-600">
|
|
<button
|
|
@click="saveMarketplaceSettings()"
|
|
:disabled="saving || !hasChanges"
|
|
class="px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700 disabled:opacity-50"
|
|
>
|
|
<span x-show="!saving">Save Marketplace Settings</span>
|
|
<span x-show="saving">Saving...</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notification Settings -->
|
|
<div x-show="activeSection === 'notifications'" class="bg-white rounded-lg shadow-xs dark:bg-gray-800">
|
|
<div class="p-4 border-b dark:border-gray-700">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200">Notification Preferences</h3>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Control how you receive notifications</p>
|
|
</div>
|
|
<div class="p-4">
|
|
<div class="space-y-4">
|
|
<!-- Email Notifications -->
|
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
<div>
|
|
<p class="font-medium text-gray-700 dark:text-gray-300">Email Notifications</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Receive important updates via email</p>
|
|
</div>
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" x-model="notificationForm.email_notifications" class="sr-only peer" />
|
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-purple-300 dark:peer-focus:ring-purple-800 rounded-full peer dark:bg-gray-600 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-500 peer-checked:bg-purple-600"></div>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Order Notifications -->
|
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
<div>
|
|
<p class="font-medium text-gray-700 dark:text-gray-300">Order Notifications</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Get notified when you receive new orders</p>
|
|
</div>
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" x-model="notificationForm.order_notifications" class="sr-only peer" />
|
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-purple-300 dark:peer-focus:ring-purple-800 rounded-full peer dark:bg-gray-600 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-500 peer-checked:bg-purple-600"></div>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Marketing Emails -->
|
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
<div>
|
|
<p class="font-medium text-gray-700 dark:text-gray-300">Marketing Emails</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">Receive tips, updates, and promotional content</p>
|
|
</div>
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" x-model="notificationForm.marketing_emails" class="sr-only peer" />
|
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-purple-300 dark:peer-focus:ring-purple-800 rounded-full peer dark:bg-gray-600 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-500 peer-checked:bg-purple-600"></div>
|
|
</label>
|
|
</div>
|
|
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 italic">
|
|
Note: Notification settings are currently display-only. Full notification management coming soon.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_scripts %}
|
|
<script src="{{ url_for('static', path='vendor/js/settings.js') }}"></script>
|
|
{% endblock %}
|