Files
orion/app/templates/vendor/settings.html
Samir Boulahtit 463e1b67d5 feat: complete vendor frontend parity with admin
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>
2026-01-01 15:34:38 +01:00

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 %}