Files
orion/app/modules/tenancy/static/vendor/js/profile.js
Samir Boulahtit 4e28d91a78 refactor: migrate templates and static files to self-contained modules
Templates Migration:
- Migrate admin templates to modules (tenancy, billing, monitoring, marketplace, etc.)
- Migrate vendor templates to modules (tenancy, billing, orders, messaging, etc.)
- Migrate storefront templates to modules (catalog, customers, orders, cart, checkout, cms)
- Migrate public templates to modules (billing, marketplace, cms)
- Keep shared templates in app/templates/ (base.html, errors/, partials/, macros/)
- Migrate letzshop partials to marketplace module

Static Files Migration:
- Migrate admin JS to modules: tenancy (23 files), core (5 files), monitoring (1 file)
- Migrate vendor JS to modules: tenancy (4 files), core (2 files)
- Migrate shared JS: vendor-selector.js to core, media-picker.js to cms
- Migrate storefront JS: storefront-layout.js to core
- Keep framework JS in static/ (api-client, utils, money, icons, log-config, lib/)
- Update all template references to use module_static paths

Naming Consistency:
- Rename static/platform/ to static/public/
- Rename app/templates/platform/ to app/templates/public/
- Update all extends and static references

Documentation:
- Update module-system.md with shared templates documentation
- Update frontend-structure.md with new module JS organization

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 14:34:16 +01:00

197 lines
5.7 KiB
JavaScript

// static/vendor/js/profile.js
/**
* Vendor profile management page logic
* Edit vendor business profile and contact information
*/
const vendorProfileLog = window.LogConfig.loggers.vendorProfile ||
window.LogConfig.createLogger('vendorProfile', false);
vendorProfileLog.info('Loading...');
function vendorProfile() {
vendorProfileLog.info('vendorProfile() called');
return {
// Inherit base layout state
...data(),
// Set page identifier
currentPage: 'profile',
// Loading states
loading: true,
error: '',
saving: false,
// Profile data
profile: null,
// Edit form
form: {
name: '',
contact_email: '',
contact_phone: '',
website: '',
business_address: '',
tax_number: '',
description: ''
},
// Form validation
errors: {},
// Track if form has changes
hasChanges: false,
async init() {
vendorProfileLog.info('Profile init() called');
// Guard against multiple initialization
if (window._vendorProfileInitialized) {
vendorProfileLog.warn('Already initialized, skipping');
return;
}
window._vendorProfileInitialized = true;
// IMPORTANT: Call parent init first to set vendorCode from URL
const parentInit = data().init;
if (parentInit) {
await parentInit.call(this);
}
try {
await this.loadProfile();
} catch (error) {
vendorProfileLog.error('Init failed:', error);
this.error = 'Failed to initialize profile page';
}
vendorProfileLog.info('Profile initialization complete');
},
/**
* Load vendor profile
*/
async loadProfile() {
this.loading = true;
this.error = '';
try {
const response = await apiClient.get(`/vendor/profile`);
this.profile = response;
this.form = {
name: response.name || '',
contact_email: response.contact_email || '',
contact_phone: response.contact_phone || '',
website: response.website || '',
business_address: response.business_address || '',
tax_number: response.tax_number || '',
description: response.description || ''
};
this.hasChanges = false;
vendorProfileLog.info('Loaded profile:', this.profile.vendor_code);
} catch (error) {
vendorProfileLog.error('Failed to load profile:', error);
this.error = error.message || 'Failed to load profile';
} finally {
this.loading = false;
}
},
/**
* Mark form as changed
*/
markChanged() {
this.hasChanges = true;
},
/**
* Validate form
*/
validateForm() {
this.errors = {};
if (!this.form.name?.trim()) {
this.errors.name = 'Business name is required';
}
if (this.form.contact_email && !this.isValidEmail(this.form.contact_email)) {
this.errors.contact_email = 'Invalid email address';
}
if (this.form.website && !this.isValidUrl(this.form.website)) {
this.errors.website = 'Invalid URL format';
}
return Object.keys(this.errors).length === 0;
},
/**
* Check if email is valid
*/
isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
},
/**
* Check if URL is valid
*/
isValidUrl(url) {
try {
new URL(url);
return true;
} catch {
return url.match(/^(https?:\/\/)?[\w-]+(\.[\w-]+)+/) !== null;
}
},
/**
* Save profile changes
*/
async saveProfile() {
if (!this.validateForm()) {
Utils.showToast('Please fix the errors before saving', 'error');
return;
}
this.saving = true;
try {
await apiClient.put(`/vendor/profile`, this.form);
Utils.showToast('Profile updated successfully', 'success');
vendorProfileLog.info('Profile updated');
this.hasChanges = false;
await this.loadProfile();
} catch (error) {
vendorProfileLog.error('Failed to save profile:', error);
Utils.showToast(error.message || 'Failed to save profile', 'error');
} finally {
this.saving = false;
}
},
/**
* Reset form to original values
*/
resetForm() {
if (this.profile) {
this.form = {
name: this.profile.name || '',
contact_email: this.profile.contact_email || '',
contact_phone: this.profile.contact_phone || '',
website: this.profile.website || '',
business_address: this.profile.business_address || '',
tax_number: this.profile.tax_number || '',
description: this.profile.description || ''
};
}
this.hasChanges = false;
this.errors = {};
}
};
}