@page "/preview/{siteid:int}" @page "/preview/{siteid:int}/{topic?}" @inherits MainPageBase @using BLAIzor.Models @using BLAIzor.Services @using Google.Cloud.Speech.V1 @using Microsoft.AspNetCore.Identity.UI.Services @using BLAIzor.Components.Partials @using System.Text @using System.Text.Json @using System.Net @using Radzen.Blazor.Rendering @* @rendermode InteractiveServer *@ @inject IEmailSender _emailService @inject NavigationManager _navigationManager @inject IHttpContextAccessor HttpContextAccessor @inject DesignTemplateService DesignTemplateService @inject CssTemplateService CssTemplateService @inject CssInjectorService CssService @inject DialogService DialogService
@{if(displayOptions) {
@currentMenuItem.Name
Happy with this look?
Not happy?
Typos?
Cancel
} else {

If you navigate to a menu item, you can save it's actual design for consitent looks, and faster load for the visitors

} }
@**@ @*

Basic information

@SiteInfo.SiteName

Site menu

Manage content
Manage design

Template: @SiteInfo.TemplateId

Page

@currentMenuItem.Name

Happy with this page?

Media
*@
Home @{ if (SiteInfo != null) { if (SiteInfo.BackgroundVideo != null) { } } } @* @if (!string.IsNullOrEmpty(dynamicallyLoadedCss)) { } *@
@*
*@
@{ if (VoiceEnabled) { if (STTEnabled) { } if (TTSEnabled) { if (!AiVoicePermitted) { } else { } } } }
@* Type anything *@ @*
*@

@{ if (!string.IsNullOrEmpty(HtmlContent.ToString())) { if (isEmailFormVisible) {
@((MarkupString)HtmlContent.ToString())
} else {
@((MarkupString)HtmlContent.ToString())
} } else {

@StatusContent

} }
@code { // public static Preview myHome; private string? Subdomain; [Parameter] public int siteid { get; set; } [Parameter] public string? topic { get; set; } private string ChatGptResponse = string.Empty; private bool isRecording = false; // private string dynamicallyLoadedCss = string.Empty; private bool displaySettingsPanel = false; private bool displayTopPanel = false; private bool displayOptions = false; private bool forceRegenerate = false; private RadzenButton button; public string DialogKey { get; set; } = "DefaultDialog"; private Dictionary _dialogSettings = new(); private readonly Dictionary _hasInitialized = new(); private void ToggleSettings() { displaySettingsPanel = !displaySettingsPanel; } private void ToggleSavedContentEdit() { displayTopPanel = !displayTopPanel; } async Task SaveCurrentLayout(MenuItem menuItem) { //Save current layout called menuItem.StoredHtml = HtmlContent.ToString(); await _logger.InfoAsync($"Preview Component: Saving layout!", $"Content length: {HtmlContent.Length}"); await _logger.InfoAsync($"Preview Component: Saving layout!", $"Content length: {menuItem.StoredHtml}"); var result = await _contentEditorService.UpdateMenuItemAsync(menuItem); var message = NotificationHelper.CreateNotificationMessage("Page design saved", 2, "Success", $"Page design for {result.Name} updated successfully"); ShowNotification(message); await _logger.InfoAsync($"Preview Component: Saved layout for page!", $"MenuItem updated with new design: {result.Id}, {result.Name}"); } private void AllowAIVoice() { AiVoicePermitted = true; } private void MuteAI() { AiVoicePermitted = false; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await jsRuntime.InvokeVoidAsync("setSessionId", SessionId); await jsRuntime.InvokeVoidAsync("initHints"); } if (_initVoicePending) { Console.WriteLine("PENDING VOICE--------------------------------------------------"); _initVoicePending = false; await jsRuntime.InvokeVoidAsync("initVoiceRecorder", "ProcessAudio2"); } } protected override Task OnInitializedAsync() { VoiceEnabled = configuration?.GetSection("AiSettings")?.GetValue("VoiceActivated") ?? false; return base.OnInitializedAsync(); } public async void MenuClick(string menuName) { await CallCSharpMethod2(menuName, SessionId, true); } public void HomeClick() { //ChatGptService.OnContentReceived -= UpdateContent; ChatGptService.OnContentReceived -= UpdateContent; _navigationManager.Refresh(true); } private void CancelEmail() { FirstColumnClass = ""; isEmailFormVisible = false; StateHasChanged(); } public Preview() { myHome = this; // Set the static reference to the current instance } protected override async Task OnParametersSetAsync() { SessionId = _scopedContentService.SessionId; SiteId = siteid; _instances[SessionId] = this; _scopedContentService.OnBrandNameChanged += HandleBrandNameChanged; SelectedBrandName = _scopedContentService.SelectedBrandName; // Subdomain = HttpContextAccessor.HttpContext?.Items["Subdomain"]?.ToString(); SiteInfo = await _contentEditorService.GetSiteInfoByIdAsync(SiteId); if (SiteInfo != null) { // SiteId = SiteInfo.Id; _scopedContentService.SelectedBrandName = SiteInfo.SiteName.ToLower(); TTSEnabled = SiteInfo.TTSActive; STTEnabled = SiteInfo.STTActive; Console.Write("Selected brand name:" + _scopedContentService.SelectedBrandName); } else { // SiteId = 1; _scopedContentService.SelectedBrandName = "default"; TTSEnabled = false; STTEnabled = false; } _scopedContentService.SelectedSiteId = SiteId; ContentCollectionName = SiteInfo.VectorCollectionName; Console.Write("------------------------"); // Load the CSS template for the selected brand from the database var designTemplate = await DesignTemplateService.GetByIdAsync((int)SiteInfo.TemplateId!); var cssTemplate = await CssTemplateService.GetByDesignTemplateIdAsync((int)SiteInfo.TemplateId); TemplateCollectionName = designTemplate.QDrandCollectionName; if (cssTemplate != null) { dynamicallyLoadedCss = cssTemplate.CssContent; // Assuming Content holds the CSS string var cssPath = await CssTemplateService.SaveTempCssFileAsync(dynamicallyLoadedCss, SessionId); await jsRuntime.InvokeVoidAsync("seemgen.injectCssFile", cssPath); } Console.Write("------------------------"); // ChatGptService.OnContentReceived += UpdateContent; ChatGptService.OnContentReceived += UpdateContent; // ChatGptService.OnStatusChangeReceived += UpdateStatus; ChatGptService.OnStatusChangeReceived += UpdateStatus; ChatGptService.OnTextContentAvailable += UpdateTextContentForVoice; Menu = await GetMenuList(SiteId); MenuItems = await GetMenuItems(SiteId); if (string.IsNullOrEmpty(HtmlContent.ToString())) { if (!string.IsNullOrWhiteSpace(topic)) { UserInput = topic; await ChatGptService.ProcessContentRequest(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, Menu, true); } else { await ChatGptService.GetChatGptWelcomeMessage(SessionId, SiteId, TemplateCollectionName, Menu); // SiteModel = await ChatGptService.InitSite(SessionId, SiteId, TemplateCollectionName, Menu); //await ChatGptService.ProcessContentRequest(SessionId, MenuItems.FirstOrDefault(), SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, Menu, true); } } UserInput = string.Empty; _initVoicePending = true; } private async void UpdateContent(string receivedSessionId, string content, MenuItem menuItem) { if (receivedSessionId == SessionId) // Only accept messages meant for this tab { HtmlContent.Clear(); HtmlContent.Append(content); //TODO SAVE TO DB if (menuItem != null) { currentMenuItem = menuItem; // IsContentSaved = string.IsNullOrEmpty(currentMenuItem.StoredHtml) ? false : true; // _logger.InfoAsync($"Preview - UpdateContent: {IsContentSaved}"); displayOptions = true; StateHasChanged(); } //InvokeAsync(StateHasChanged); // Ensures UI updates dynamically await InvokeAsync(() => { StateHasChanged(); }); var result = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); _scopedContentService.CurrentDOM = JsonSerializer.Serialize(result); //_scopedContentService.CurrentDOM = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); } } // private async void UpdateTextContentForVoice(string receivedSessionId, string content) // { // if (receivedSessionId == SessionId) // Only accept messages meant for this tab // { // TextContent = content; // await ConvertTextToSpeech(content); // //_scopedContentService.CurrentDOM = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); // } // } private async void UpdateFinished(string receivedSessionId) { if (receivedSessionId == SessionId) // Only accept messages meant for this tab { Console.WriteLine("Content update finished"); var result = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); _scopedContentService.CurrentDOM = JsonSerializer.Serialize(result); Console.Write(_scopedContentService.CurrentDOM); } } private async Task ContentChangedInForm() { var result = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); _scopedContentService.CurrentDOM = JsonSerializer.Serialize(result); Console.Write(_scopedContentService.CurrentDOM); } private async void UpdateStatus(string receivedSessionId, string content) { if (receivedSessionId == SessionId) // Only accept messages meant for this tab { StatusContent = content; //InvokeAsync(StateHasChanged); // Ensures UI updates dynamically await InvokeAsync(() => { StateHasChanged(); }); } } public async Task Enter(KeyboardEventArgs e) { if (e.Code == "Enter" || e.Code == "NumpadEnter") { HtmlContent.Clear(); var menu = await GetMenuList(SiteId); await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, menu); UserInput = string.Empty; } } // public void Dispose() // { // dynamicallyLoadedCss = ""; // HtmlContent.Clear(); // _scopedContentService.OnBrandNameChanged -= HandleBrandNameChanged; // AIService.OnContentReceived -= UpdateContent; // AIService.OnStatusChangeReceived -= UpdateStatus; public async ValueTask DisposeAsync() { dynamicallyLoadedCss = ""; HtmlContent.Clear(); await CssTemplateService.DeleteSessionCssFile(SessionId); _scopedContentService.OnBrandNameChanged -= HandleBrandNameChanged; ChatGptService.OnContentReceived -= UpdateContent; ChatGptService.OnContentReceiveFinished -= UpdateFinished; ChatGptService.OnStatusChangeReceived -= UpdateStatus; ChatGptService.OnTextContentAvailable -= UpdateTextContentForVoice; } // public async ValueTask DisposeAsync() // { // await CssTemplateService.DeleteSessionCssFile(SessionId); // } public async Task EditSite() { string dialogKey = $"EditSiteInfoDialogSettings_{siteid}"; // can be anything unique var settings = await LoadStateAsync(dialogKey) ?? new EditSiteInfoDialogSettings { Width = "500px", Height = "512px", Left = "10%", Top = "10%" }; await DialogService.OpenAsync($"Edit information of {SiteInfo.SiteName}", new Dictionary() { { "SiteId", siteid }, { "OnSiteNameChanged", new Func(OnSiteNameChanged) }, { "OnSiteInfoSaveClicked", new Func(OnSiteInfoSaved) }, }, new DialogOptions() { Resizable = true, Draggable = true, Resize = GetResizeHandler(dialogKey), Drag = GetDragHandler(dialogKey), Width = settings.Width, Height = settings.Height, Left = settings.Left, Top = settings.Top, CssClass = "draggable-popup-dialog", WrapperCssClass = "draggable-popup-dialog-wrapper" }); await SaveStateAsync(dialogKey, _editSiteinfoSettings); } public async Task EditMenu() { string dialogKey = $"EditMenuDialogSettings_{siteid}"; // can be anything unique var settings = await LoadStateAsync(dialogKey) ?? new EditSiteInfoDialogSettings { Width = "500px", Height = "512px", Left = "10%", Top = "10%" }; await DialogService.OpenAsync($"Edit menu of {SiteInfo.SiteName}", new Dictionary() { { "SiteId", siteid }, { "SessionId", SessionId }, // { "OnSiteNameChanged", new Func(OnSiteNameChanged) }, // { "OnSiteInfoSaveClicked", new Func(OnSiteInfoSaved) }, }, new DialogOptions() { Resizable = true, Draggable = true, Resize = GetResizeHandler(dialogKey), Drag = GetDragHandler(dialogKey), Width = settings.Width, Height = settings.Height, Left = settings.Left, Top = settings.Top, CssClass = "draggable-popup-dialog", WrapperCssClass = "draggable-popup-dialog-wrapper" }); await SaveStateAsync(dialogKey, _editSiteinfoSettings); } private async Task OnSiteNameChanged(string newName) { Console.WriteLine("Sitename updated!!!!!!"); SelectedBrandName = newName; } private async Task OnSiteInfoSaved(SiteInfo newInfo) { Console.WriteLine("Sitename updated!!!!!!"); var message = NotificationHelper.CreateNotificationMessage("Site information saved", 2, "Success", "Site information saved successfully"); ShowNotification(message); } public async Task EditContentItem(int Id) { string dialogKey = $"EditContentItemDialogSettings_{Id}"; // can be anything unique var settings = await LoadStateAsync(dialogKey) ?? new EditSiteInfoDialogSettings { Width = "70vw", Height = "80vh", Left = "10%", Top = "10%" }; await DialogService.OpenAsync($"Edit content {Id}", new Dictionary() { { "ContentItemId", Id }, { "OnContentUpdated", new Func(OnContentItemUpdated) }, { "OnSaved", new Func(OnContentItemSaved) }, { "OnCancelled", new Func(OnEditContentItemCancelClicked) }, }, new DialogOptions() { Resizable = true, Draggable = true, Resize = GetResizeHandler(dialogKey), Drag = GetDragHandler(dialogKey), Width = settings.Width, Height = settings.Height, Left = settings.Left, Top = settings.Top, CssClass = "draggable-popup-dialog", WrapperCssClass = "draggable-popup-dialog-wrapper" }); await SaveStateAsync(dialogKey, _editSiteinfoSettings); } private async Task OnContentItemUpdated(ContentItem contentGroup) { } private async Task OnContentItemSaved(ContentItem contentGroup) { //TODO Cahce outdated await CacheService.UpdateContentCache(SessionId, SiteId); var message = NotificationHelper.CreateNotificationMessage("ContentItem saved", 2, "Success", "ContentItem saved successfully"); ShowNotification(message); } private async Task OnEditContentItemCancelClicked() { Console.WriteLine("ContentItem Edit clicked"); } public async Task OpenManageContentGroups() { string dialogKey = $"ManageContentGroupsDialogSettings_{siteid}"; // can be anything unique var settings = await LoadStateAsync(dialogKey); if (settings != null) { Console.WriteLine($"Settings: {settings.Top}, {settings.Left}, {settings.Height}, {settings.Width}"); } else { settings = new EditSiteInfoDialogSettings { Width = "300px", Height = "612px", Left = "10%", Top = "10%" }; } await DialogService.OpenAsync($"Manage content of {SiteInfo.SiteName}", new Dictionary() { { "SiteInfoId", siteid }, { "OnManageContentItemClicked", new Func(OnManageContentItemClicked) } }, new DialogOptions() { Resizable = true, Draggable = true, Resize = GetResizeHandler(dialogKey), Drag = GetDragHandler(dialogKey), Width = settings.Width, Height = settings.Height, Left = settings.Left, Top = settings.Top, CssClass = "draggable-popup-dialog", WrapperCssClass = "draggable-popup-dialog-wrapper" }); await SaveStateAsync(dialogKey, _editSiteinfoSettings); } private async Task OnContentGroupUpdated(ContentGroup contentGroup) { Console.WriteLine("ContentGroup updated!!!!!!"); } private async Task OnContentGroupEditStarted(ContentGroup contentGroup) { Console.WriteLine("ContentGroup edit started!!!!!!"); } private async Task OnManageContentItemClicked(string methodName, int Id) { Console.WriteLine("ContentItem Edit clicked"); await EditContentItem(Id); } public async Task OpenManageUploads() { string dialogKey = $"ManageUploadsDialogSettings_{siteid}"; // can be anything unique var settings = await LoadStateAsync(dialogKey) ?? new EditSiteInfoDialogSettings { Width = "600px", Height = "600px", Left = "10%", Top = "10%" }; await DialogService.OpenAsync($"Media library", null, new DialogOptions() { Resizable = true, Draggable = true, Resize = GetResizeHandler(dialogKey), Drag = GetDragHandler(dialogKey), Width = settings.Width, Height = settings.Height, Left = settings.Left, Top = settings.Top, CssClass = "draggable-popup-dialog", WrapperCssClass = "draggable-popup-dialog-wrapper" }); await SaveStateAsync(dialogKey, _editSiteinfoSettings); } public async Task OpenContentEditor(MenuItem currentMenuItem) { string dialogKey = $"HtmlContentEditorSettings_{siteid}"; // can be anything unique // var settings = await LoadStateAsync(dialogKey) ?? new EditSiteInfoDialogSettings { Width = "600px", Height = "600px", Left = "10%", Top = "10%" }; await DialogService.OpenAsync($"Edit the content of this page", new Dictionary() { { "Html", currentMenuItem.StoredHtml }, { "HtmlChanged", new Func(OnHtmlUpdated) } }, new DialogOptions() { Resizable = true, Draggable = true, Resize = GetResizeHandler(dialogKey), Drag = GetDragHandler(dialogKey), Width = settings.Width, Height = settings.Height, Left = settings.Left, Top = settings.Top, CssClass = "draggable-popup-dialog", WrapperCssClass = "draggable-popup-dialog-wrapper" }); await SaveStateAsync(dialogKey, _editSiteinfoSettings); } private async Task OnHtmlUpdated(string newHtml) { HtmlContent.Clear(); HtmlContent.Append(newHtml); // You can trigger embedding regeneration, saving, etc. currentMenuItem.StoredHtml = newHtml; var result = await _contentEditorService.UpdateMenuItemAsync(currentMenuItem); var message = NotificationHelper.CreateNotificationMessage("Content saved", 2, "Success", "Static content saved successfully"); ShowNotification(message); } private Action GetDragHandler(string key) { return (point) => { if (!_hasInitialized.ContainsKey(key)) { _hasInitialized[key] = true; Console.WriteLine($"🚫 Skipping initial drag for {key}"); return; } var settings = GetSettingsForKey(key); Console.WriteLine($"Got settings: {settings.Top}, {settings.Left}, {settings.Height}, {settings.Width}"); settings.Left = $"{point.X}px"; settings.Top = $"{point.Y}px"; Console.WriteLine($"NEW Settings: {settings.Top}, {settings.Left}, {settings.Height}, {settings.Width}"); _dialogSettings[key] = settings; InvokeAsync(() => SaveStateAsync(key, settings)); }; } private Action GetResizeHandler(string key) { return (size) => { if (!_hasInitialized.ContainsKey(key)) { _hasInitialized[key] = true; Console.WriteLine($"🚫 Skipping initial resize for {key}"); return; } var settings = GetSettingsForKey(key); Console.WriteLine($"Got settings: {settings.Top}, {settings.Left}, {settings.Height}, {settings.Width}"); settings.Width = $"{size.Width}px"; settings.Height = $"{size.Height}px"; Console.WriteLine($"NEW Settings: {settings.Top}, {settings.Left}, {settings.Height}, {settings.Width}"); _dialogSettings[key] = settings; InvokeAsync(() => SaveStateAsync(key, settings)); }; } private EditSiteInfoDialogSettings GetSettingsForKey(string key) { Console.WriteLine($"Getting settings for {key}"); if (_dialogSettings.TryGetValue(key, out var value)) return value; var newSettings = new EditSiteInfoDialogSettings(); _dialogSettings[key] = newSettings; return newSettings; } // void OnDrag(System.Drawing.Point point) // { // jsRuntime.InvokeVoidAsync("eval", $"console.log('Dialog drag. Left:{point.X}, Top:{point.Y}')"); // if (EditSiteInfoSettings == null) // { // EditSiteInfoSettings = new EditSiteInfoDialogSettings(); // } // EditSiteInfoSettings.Left = $"{point.X}px"; // EditSiteInfoSettings.Top = $"{point.Y}px"; // InvokeAsync(() => SaveStateAsync(DialogKey, EditSiteInfoSettings)); // } // void OnResize(System.Drawing.Size size) // { // jsRuntime.InvokeVoidAsync("eval", $"console.log('Dialog resize. Width:{size.Width}, Height:{size.Height}')"); // if (EditSiteInfoSettings == null) // { // EditSiteInfoSettings = new EditSiteInfoDialogSettings(); // } // EditSiteInfoSettings.Width = $"{size.Width}px"; // EditSiteInfoSettings.Height = $"{size.Height}px"; // InvokeAsync(() => SaveStateAsync(DialogKey, EditSiteInfoSettings)); // } private EditSiteInfoDialogSettings _editSiteinfoSettings = new(); public EditSiteInfoDialogSettings EditSiteInfoSettings { get => _editSiteinfoSettings; set { if (_editSiteinfoSettings != value) { _editSiteinfoSettings = value; InvokeAsync(() => SaveStateAsync(DialogKey, _editSiteinfoSettings)); } } } // private async Task LoadStateAsync() // { // await Task.CompletedTask; // var result = await jsRuntime.InvokeAsync("window.localStorage.getItem", "EditSiteInfoDialogSettings"); // if (!string.IsNullOrEmpty(result)) // { // _editSiteinfoSettings = JsonSerializer.Deserialize(result); // } // } // private async Task SaveStateAsync() // { // await Task.CompletedTask; // await jsRuntime.InvokeVoidAsync("window.localStorage.setItem", "EditSiteInfoDialogSettings", JsonSerializer.Serialize(EditSiteInfoSettings)); // } private async Task LoadStateAsync(string dialogKey) { Console.WriteLine($"Loading setting for {dialogKey}"); var result = await jsRuntime.InvokeAsync("window.localStorage.getItem", dialogKey); if (!string.IsNullOrEmpty(result)) { Console.WriteLine($"Found setting for {dialogKey}"); return JsonSerializer.Deserialize(result); } return null; } private async Task SaveStateAsync(string dialogKey, EditSiteInfoDialogSettings settings) { if (string.IsNullOrEmpty(settings?.Width) || string.IsNullOrEmpty(settings?.Height) || string.IsNullOrEmpty(settings?.Top) || string.IsNullOrEmpty(settings?.Left)) { Console.WriteLine($"❌ Skipping save for {dialogKey} due to invalid values"); return; // Do NOT save garbage data } Console.WriteLine($"Saving setting for {dialogKey}"); var json = JsonSerializer.Serialize(settings); Console.WriteLine($"Saving ettings: {settings.Top}, {settings.Left}, {settings.Height}, {settings.Width}, {json}"); await jsRuntime.InvokeVoidAsync("window.localStorage.setItem", dialogKey, json); } public class EditSiteInfoDialogSettings { public string Left { get; set; } public string Top { get; set; } public string Width { get; set; } public string Height { get; set; } } }