Skip to content

Commit

Permalink
Solara
Browse files Browse the repository at this point in the history
  • Loading branch information
ideyaa committed Sep 6, 2024
1 parent 9a8ce70 commit 5e8ede1
Show file tree
Hide file tree
Showing 5 changed files with 582 additions and 543 deletions.
168 changes: 168 additions & 0 deletions solara/lib/core/dashboard/brand/BrandController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// BrandController.js
class BrandController {
constructor(model, view) {
this.model = model;
this.view = view;
this.onSectionChanged = this.onSectionChanged.bind(this);
this.deleteField = this.deleteField.bind(this);
this.initializeEventListeners();
this.view.setOnSectionChangedHandler(this.onSectionChanged);
this.view.setOnDeleteFieldHandler(this.deleteField);
}

async initializeApp() {
this.model.brandKey = this.model.getQueryFromUrl('brand_key');
this.model.source = this.model.getQueryFromUrl('source') || 'remote';

try {
const { sectionItems, brandName } = await this.model.fetchSections();
this.view.updateAppNameTitle(brandName);
await this.loadSections(sectionItems);

const { isCurrentBrand, contentChanged } = await this.model.fetchCurrentBrand();
if (!isCurrentBrand) {
this.view.showSwitchButton();
} else if (contentChanged) {
this.view.showApplyChangesButton();
}

await this.checkBrandHealth();
} catch (error) {
console.error('Error initializing app:', error);
alert(error.message);
}
}

initializeEventListeners() {
document.getElementById('allBrandsButton').addEventListener('click', () => {
window.location.href = `../brands/brands.html?source=${this.model.source}`;
});

document.getElementById('applyChangesButton').addEventListener('click', () => this.switchToBrand());
document.getElementById('switchButton').addEventListener('click', () => this.switchToBrand());
}

async loadSections(sectionItems) {
try {
for (let i = 0; i < sectionItems.length; i++) {
const sectionInfo = sectionItems[i];
console.log('Processing section:', i, sectionInfo);

const sectionElement = this.view.createSection(sectionInfo.name, sectionInfo.type, sectionInfo.subtitle);
this.view.sectionsContainer.appendChild(sectionElement);

console.log('Section element created:', sectionElement);

this.view.populateSection(sectionInfo, sectionElement, sectionInfo.content, sectionInfo.name, sectionInfo.type, sectionInfo.inputType);

const addButton = document.createElement('button');
addButton.textContent = 'Add Field';
addButton.className = 'add-field-btn';
addButton.onclick = () => this.addNewField(sectionInfo, sectionElement, sectionInfo.name, sectionInfo.type, sectionInfo.inputType);
sectionElement.appendChild(addButton);
}
} catch (error) {
console.error('Error loading sections:', error);
alert(error.message);
}
}

async onSectionChanged(sectionItem, sectionElement, sectionName, sectionType) {
console.log('onSectionChanged called with:', this);
try {
const configuration = this.getSectionConfiguration(sectionElement);
await this.model.saveSection(sectionItem, configuration);
this.view.showApplyChangesButton();
await this.checkBrandHealth();
} catch (error) {
console.error('Error saving section:', error);
alert(error.message);
}
}

getSectionConfiguration(sectionElement) {
const configuration = {};
const inputs = sectionElement.querySelectorAll('input:not(.array-item-input)');
inputs.forEach(input => {
const keys = input.id.split('.');
let current = configuration;
for (let i = 0; i < keys.length - 1; i++) {
if (!current[keys[i]]) {
current[keys[i]] = {};
}
current = current[keys[i]];
}
const lastKey = keys[keys.length - 1];

if (input.classList.contains('array-input')) {
const arrayItemsContainer = input.closest('.input-wrapper').querySelector('.array-items-container');
current[lastKey] = this.getArrayValue(arrayItemsContainer);
} else {
let value = input.value;
if (input.type === 'color') {
value = `#${value.substring(1).toUpperCase()}`;
}
current[lastKey] = value;
}
});
return configuration;
}

addNewField(sectionItem, sectionElement, sectionName, sectionType, inputType) {
this.view.showAddFieldForm(sectionItem, sectionElement, sectionName, sectionType, inputType);
}

deleteField(sectionItem, fieldContainer, sectionName, sectionType) {
this.view.showConfirmationDialog(
'Are you sure you want to delete this item?',
() => {
const sectionElement = fieldContainer.closest('.section');
fieldContainer.remove();
this.onSectionChanged(sectionItem, sectionElement, sectionName, sectionType);
}
);
}

getArrayValue(container) {
const arrayItems = container.querySelectorAll('.array-item-input');
return Array.from(arrayItems).map(item => item.value);
}

async switchToBrand() {
try {
await this.model.switchToBrand();
const applyChangesButton = document.getElementById('applyChangesButton');
applyChangesButton.style.display = 'none';
location.reload();
} catch (error) {
console.error('Error switching to brand:', error);
alert(error.message);
}
}

async checkBrandHealth() {
try {
const result = await this.model.checkBrandHealth();
const errorButton = document.getElementById('error-button');

if (!result.passed) {
errorButton.style.display = "flex";
const errors = result.errors
.map((error, index) => `${index + 1}. ${error}`)
.join('\n');
this.view.updateErrorCount(result.errors.length);

errorButton.onclick = () => {
this.view.showMessage(`Health check for all brands completed with errors: \n\n${errors}`);
};
} else {
errorButton.style.display = "none";
}
} catch (error) {
console.error('Error checking brand health:', error);
alert(error.message);
}
}
}

export default BrandController;
131 changes: 131 additions & 0 deletions solara/lib/core/dashboard/brand/BrandModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// BrandModel.js
class BrandModel {
constructor() {
this.sectionItems = [];
this.brandName = '';
this.brandKey = '';
this.isCurrentBrand = false;
this.source = 'remote';
this.savingInProgress = false;
}

getQueryFromUrl(name) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(name);
}

async fetchSections() {
try {
if (!this.brandKey) {
throw new Error('No brand_key provided in URL');
}

const url = `/sections?brand_key=${encodeURIComponent(this.brandKey)}`;
console.log('Fetching sections from:', url);

const response = await fetch(url);
const result = await response.json();
if (!response.ok) {
throw new Error(result.error);
}
this.sectionItems = result.result.sections;
this.brandName = result.result.brand_name;
return { sectionItems: this.sectionItems, brandName: this.brandName };
} catch (error) {
console.error('Error fetching config sections:', error);
throw error;
}
}

async fetchCurrentBrand() {
try {
const response = await fetch('/brand/current');
let result = await response.json();
if (!response.ok) {
throw new Error(result.error);
}
this.isCurrentBrand = result.key === this.brandKey;
return { isCurrentBrand: this.isCurrentBrand, contentChanged: result.content_changed };
} catch (error) {
console.error('Error fetching current brand:', error);
throw error;
}
}

async saveSection(sectionItem, configuration) {
if (this.savingInProgress) return;
this.savingInProgress = true;

const dataToSend = {
brand_key: this.brandKey,
key: sectionItem.key,
data: configuration
};

try {
const response = await fetch(`/section/edit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(dataToSend)
});

const result = await response.json();

if (!response.ok) {
throw new Error(result.error);
}

console.log(`${sectionItem.name} configuration saved successfully!`);
return true;
} catch (error) {
console.error('Error saving configuration:', error);
throw error;
} finally {
this.savingInProgress = false;
}
}

async switchToBrand() {
try {
const response = await fetch('/switch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({brand_key: this.brandKey}),
});

const result = await response.json();

if (!response.ok) {
throw new Error(result.error);
}

console.log('Switch to brand result:', result);
return true;
} catch (error) {
console.error('Error switching to brand:', error);
throw error;
}
}

async checkBrandHealth() {
try {
const response = await fetch(`/brand/doctor?brand_key=${encodeURIComponent(this.brandKey)}`);
const result = await response.json();

if (!response.ok) {
throw new Error(result.error);
}

return result.result;
} catch (error) {
console.error('Error calling doctor API:', error);
throw error;
}
}
}

export default BrandModel;
Loading

0 comments on commit 5e8ede1

Please sign in to comment.