mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:21:10 +02:00
🔥 remove: demo mode from todo, contacts, clock, questions, chat apps
- Enforce login redirect for unauthenticated users - Remove demo banner, AuthGateModal, and GuestWelcomeModal - Remove guest mode state variables and CSS styles - Simplify showLogout to always show when user is logged in Affected apps: todo-web, contacts-web, clock-web, questions-web, chat-web
This commit is contained in:
parent
68219a01df
commit
f07387d12c
5 changed files with 76 additions and 603 deletions
|
|
@ -24,11 +24,6 @@
|
|||
import { getPillAppItems } from '@manacore/shared-branding';
|
||||
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||
import {
|
||||
AuthGateModal,
|
||||
GuestWelcomeModal,
|
||||
shouldShowGuestWelcome,
|
||||
} from '@manacore/shared-auth-ui';
|
||||
import type { LayoutData } from './$types';
|
||||
|
||||
// App switcher items
|
||||
|
|
@ -40,17 +35,6 @@
|
|||
let isSidebarMode = $state(false);
|
||||
let isCollapsed = $state(false);
|
||||
|
||||
// Guest mode state
|
||||
let showAuthGateModal = $state(false);
|
||||
let authGateAction = $state<'save' | 'sync' | 'ai' | 'feature'>('ai');
|
||||
|
||||
// Guest welcome modal state
|
||||
let showGuestWelcome = $state(false);
|
||||
|
||||
// Check if in guest mode
|
||||
let isGuestMode = $derived(!authStore.isAuthenticated);
|
||||
let sessionConversationCount = $derived(sessionConversationsStore.count);
|
||||
|
||||
// Use theme store's isDark directly
|
||||
let isDark = $derived(theme.isDark);
|
||||
|
||||
|
|
@ -170,8 +154,15 @@
|
|||
goto('/login');
|
||||
}
|
||||
|
||||
// Initialize on mount - supports both authenticated and guest mode
|
||||
// Initialize on mount - enforce login
|
||||
onMount(async () => {
|
||||
// Initialize auth and redirect if not authenticated
|
||||
await authStore.initialize();
|
||||
if (!authStore.isAuthenticated) {
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize theme
|
||||
theme.initialize();
|
||||
|
||||
|
|
@ -189,27 +180,18 @@
|
|||
collapsedStore.set(true);
|
||||
}
|
||||
|
||||
await authStore.initialize();
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Show guest welcome modal for unauthenticated users
|
||||
if (!authStore.isAuthenticated && shouldShowGuestWelcome('chat')) {
|
||||
showGuestWelcome = true;
|
||||
// Check for session conversations to migrate
|
||||
if (conversationsStore.hasSessionConversations) {
|
||||
await conversationsStore.migrateSessionConversations();
|
||||
}
|
||||
|
||||
// Load user settings if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
await userSettings.load();
|
||||
|
||||
// Check for session conversations to migrate
|
||||
if (conversationsStore.hasSessionConversations) {
|
||||
await conversationsStore.migrateSessionConversations();
|
||||
}
|
||||
|
||||
// Redirect to start page if on /chat and a custom start page is set
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath === '/chat' && userSettings.startPage && userSettings.startPage !== '/chat') {
|
||||
goto(userSettings.startPage, { replaceState: true });
|
||||
}
|
||||
// Redirect to start page if on /chat and a custom start page is set
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath === '/chat' && userSettings.startPage && userSettings.startPage !== '/chat') {
|
||||
goto(userSettings.startPage, { replaceState: true });
|
||||
}
|
||||
|
||||
isChecking = false;
|
||||
|
|
@ -229,22 +211,8 @@
|
|||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Guest Mode Banner -->
|
||||
{#if isGuestMode}
|
||||
<div class="guest-banner">
|
||||
<span>
|
||||
Du bist im Gast-Modus.
|
||||
{#if sessionConversationCount > 0}
|
||||
{sessionConversationCount}
|
||||
{sessionConversationCount === 1 ? 'Unterhaltung' : 'Unterhaltungen'} in dieser Session.
|
||||
{/if}
|
||||
</span>
|
||||
<button onclick={() => goto('/login')}>Anmelden</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Navigation Layout -->
|
||||
<div class="layout-container" class:has-guest-banner={isGuestMode}>
|
||||
<div class="layout-container">
|
||||
<!-- Floating/Sidebar Pill Navigation -->
|
||||
<PillNavigation
|
||||
items={navItems}
|
||||
|
|
@ -296,91 +264,15 @@
|
|||
{/if}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Auth Gate Modal -->
|
||||
<AuthGateModal
|
||||
visible={showAuthGateModal}
|
||||
onClose={() => (showAuthGateModal = false)}
|
||||
onLogin={() => {
|
||||
showAuthGateModal = false;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem('auth-return-url', window.location.pathname);
|
||||
}
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showAuthGateModal = false;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem('auth-return-url', window.location.pathname);
|
||||
}
|
||||
goto('/register');
|
||||
}}
|
||||
action={authGateAction}
|
||||
migrationCount={sessionConversationCount}
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
/>
|
||||
|
||||
<!-- Guest Welcome Modal -->
|
||||
<GuestWelcomeModal
|
||||
appId="chat"
|
||||
visible={showGuestWelcome}
|
||||
onClose={() => (showGuestWelcome = false)}
|
||||
onLogin={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/register');
|
||||
}}
|
||||
helpHref="/help"
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.guest-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 60;
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.guest-banner button {
|
||||
background-color: white;
|
||||
color: #3b82f6;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s;
|
||||
}
|
||||
|
||||
.guest-banner button:hover {
|
||||
background-color: #f0f9ff;
|
||||
}
|
||||
|
||||
.layout-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.layout-container.has-guest-banner {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
transition: all 300ms ease;
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@
|
|||
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||
import { alarmsApi } from '$lib/api/alarms';
|
||||
import { timersApi } from '$lib/api/timers';
|
||||
import AuthGateModal from '$lib/components/AuthGateModal.svelte';
|
||||
import { GuestWelcomeModal, shouldShowGuestWelcome } from '@manacore/shared-auth-ui';
|
||||
|
||||
// App switcher items
|
||||
const appItems = getPillAppItems('clock');
|
||||
|
|
@ -119,20 +117,6 @@
|
|||
let isSidebarMode = $state(false);
|
||||
let isCollapsed = $state(false);
|
||||
|
||||
// Guest mode state
|
||||
let showAuthGateModal = $state(false);
|
||||
let authGateAction = $state<'save' | 'sync' | 'feature'>('save');
|
||||
|
||||
// Guest welcome modal state
|
||||
let showGuestWelcome = $state(false);
|
||||
|
||||
// Check if in guest mode
|
||||
let isGuestMode = $derived(!authStore.isAuthenticated);
|
||||
let sessionItemCount = $derived(sessionAlarmsStore.count + sessionTimersStore.count);
|
||||
|
||||
// Language for GuestWelcomeModal
|
||||
let currentLocale = $derived($locale || 'de');
|
||||
|
||||
// Use theme store's isDark directly
|
||||
let isDark = $derived(theme.isDark);
|
||||
|
||||
|
|
@ -195,7 +179,7 @@
|
|||
{ href: '/feedback', label: 'Feedback', icon: 'chat' },
|
||||
];
|
||||
|
||||
// Navigation items filtered by visibility settings (with fallback for guest mode)
|
||||
// Navigation items filtered by visibility settings
|
||||
const navItems = $derived(
|
||||
filterHiddenNavItems('clock', baseNavItems, userSettings.nav?.hiddenNavItems || {})
|
||||
);
|
||||
|
|
@ -259,6 +243,13 @@
|
|||
}
|
||||
|
||||
onMount(async () => {
|
||||
// Initialize auth and redirect if not authenticated
|
||||
await authStore.initialize();
|
||||
if (!authStore.isAuthenticated) {
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('clock-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
|
|
@ -273,49 +264,28 @@
|
|||
collapsedStore.set(true);
|
||||
}
|
||||
|
||||
// Show guest welcome modal for unauthenticated users
|
||||
if (!authStore.isAuthenticated && shouldShowGuestWelcome('clock')) {
|
||||
showGuestWelcome = true;
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Check for session data to migrate
|
||||
if (alarmsStore.hasSessionAlarms) {
|
||||
await alarmsStore.migrateSessionAlarms();
|
||||
}
|
||||
if (timersStore.hasSessionTimers) {
|
||||
await timersStore.migrateSessionTimers();
|
||||
}
|
||||
|
||||
// Load user settings if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
await userSettings.load();
|
||||
|
||||
// Check for session data to migrate
|
||||
if (alarmsStore.hasSessionAlarms) {
|
||||
await alarmsStore.migrateSessionAlarms();
|
||||
}
|
||||
if (timersStore.hasSessionTimers) {
|
||||
await timersStore.migrateSessionTimers();
|
||||
}
|
||||
|
||||
// Redirect to start page if on root and a custom start page is set
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath === '/' && userSettings.startPage && userSettings.startPage !== '/') {
|
||||
goto(userSettings.startPage, { replaceState: true });
|
||||
}
|
||||
// Redirect to start page if on root and a custom start page is set
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath === '/' && userSettings.startPage && userSettings.startPage !== '/') {
|
||||
goto(userSettings.startPage, { replaceState: true });
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window onkeydown={handleKeydown} />
|
||||
|
||||
<!-- Guest Mode Banner -->
|
||||
{#if isGuestMode}
|
||||
<div class="guest-banner">
|
||||
<span>
|
||||
Du bist im Gast-Modus.
|
||||
{#if sessionItemCount > 0}
|
||||
{sessionItemCount}
|
||||
{sessionItemCount === 1 ? 'Element' : 'Elemente'} in dieser Session.
|
||||
{/if}
|
||||
</span>
|
||||
<button onclick={() => goto('/login')}>Anmelden</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="layout-container" class:has-guest-banner={isGuestMode}>
|
||||
<div class="layout-container">
|
||||
<PillNavigation
|
||||
items={navItems}
|
||||
currentPath={$page.url.pathname}
|
||||
|
|
@ -337,7 +307,7 @@
|
|||
showLanguageSwitcher={true}
|
||||
{languageItems}
|
||||
{currentLanguageLabel}
|
||||
showLogout={authStore.isAuthenticated}
|
||||
showLogout={true}
|
||||
onLogout={handleLogout}
|
||||
loginHref="/login"
|
||||
primaryColor="#f59e0b"
|
||||
|
|
@ -371,76 +341,15 @@
|
|||
emptyText="Keine Ergebnisse"
|
||||
searchingText="Suche..."
|
||||
/>
|
||||
|
||||
<!-- Auth Gate Modal -->
|
||||
<AuthGateModal
|
||||
open={showAuthGateModal}
|
||||
action={authGateAction}
|
||||
itemCount={sessionItemCount}
|
||||
onClose={() => (showAuthGateModal = false)}
|
||||
/>
|
||||
|
||||
<!-- Guest Welcome Modal -->
|
||||
<GuestWelcomeModal
|
||||
appId="clock"
|
||||
visible={showGuestWelcome}
|
||||
onClose={() => (showGuestWelcome = false)}
|
||||
onLogin={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/register');
|
||||
}}
|
||||
helpHref="/help"
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.guest-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 60;
|
||||
background-color: #f59e0b;
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.guest-banner button {
|
||||
background-color: white;
|
||||
color: #f59e0b;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s;
|
||||
}
|
||||
|
||||
.guest-banner button:hover {
|
||||
background-color: #fef3c7;
|
||||
}
|
||||
|
||||
.layout-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.layout-container.has-guest-banner {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
transition: all 300ms ease;
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -46,12 +46,6 @@
|
|||
formatParsedContactPreview,
|
||||
} from '$lib/utils/contact-parser';
|
||||
import ContactsToolbar from '$lib/components/ContactsToolbar.svelte';
|
||||
import {
|
||||
AuthGateModal,
|
||||
GuestWelcomeModal,
|
||||
shouldShowGuestWelcome,
|
||||
} from '@manacore/shared-auth-ui';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// Tags state for Quick-Create
|
||||
let availableTags = $state<{ id: string; name: string }[]>([]);
|
||||
|
|
@ -216,31 +210,6 @@
|
|||
goto('/login');
|
||||
}
|
||||
|
||||
// Auth gate modal state
|
||||
let showAuthGateModal = $state(false);
|
||||
let authGateAction = $state<'save' | 'sync' | 'feature'>('save');
|
||||
|
||||
// Guest welcome modal state
|
||||
let showGuestWelcome = $state(false);
|
||||
|
||||
// Show auth gate modal (can be called from child components)
|
||||
function showAuthGate(action: 'save' | 'sync' | 'feature' = 'save') {
|
||||
authGateAction = action;
|
||||
showAuthGateModal = true;
|
||||
}
|
||||
|
||||
// Listen for show-auth-gate events from child components
|
||||
$effect(() => {
|
||||
if (browser) {
|
||||
const handler = (e: Event) => {
|
||||
const customEvent = e as CustomEvent<{ action?: 'save' | 'sync' | 'feature' }>;
|
||||
showAuthGate(customEvent.detail?.action || 'save');
|
||||
};
|
||||
window.addEventListener('show-auth-gate', handler);
|
||||
return () => window.removeEventListener('show-auth-gate', handler);
|
||||
}
|
||||
});
|
||||
|
||||
async function handleCloseContactModal() {
|
||||
// Refresh contacts list in case something was changed
|
||||
await contactsStore.loadContacts();
|
||||
|
|
@ -301,6 +270,13 @@
|
|||
}
|
||||
|
||||
onMount(async () => {
|
||||
// Initialize auth and redirect if not authenticated
|
||||
await authStore.initialize();
|
||||
if (!authStore.isAuthenticated) {
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize split-panel from URL/localStorage
|
||||
splitPanel.initialize();
|
||||
|
||||
|
|
@ -309,13 +285,7 @@
|
|||
viewModeStore.initialize();
|
||||
contactsFilterStore.initialize();
|
||||
|
||||
// Show guest welcome modal for unauthenticated users
|
||||
if (!authStore.isAuthenticated && shouldShowGuestWelcome('contacts')) {
|
||||
showGuestWelcome = true;
|
||||
}
|
||||
|
||||
// Only fetch user data if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
// Fetch user data
|
||||
// Load user settings and tags
|
||||
await userSettings.load();
|
||||
|
||||
|
|
@ -357,41 +327,6 @@
|
|||
<SplitPaneContainer>
|
||||
<!-- Navigation Layout -->
|
||||
<div class="layout-container">
|
||||
<!-- Demo Mode Banner -->
|
||||
{#if !authStore.isAuthenticated}
|
||||
<div
|
||||
class="guest-banner bg-primary/10 border-primary/20 fixed top-0 right-0 left-0 z-50 flex items-center justify-between border-b px-4 py-2"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<svg class="text-primary h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-foreground">
|
||||
<strong>Demo-Modus</strong>
|
||||
<span class="text-muted-foreground hidden sm:inline">
|
||||
- Beispiel-Kontakte zum Ausprobieren
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onclick={() => showAuthGate('save')}
|
||||
class="bg-primary text-primary-foreground hover:bg-primary/90 rounded-md px-3 py-1 text-sm font-medium transition-colors"
|
||||
>
|
||||
Anmelden
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- UI Elements (hidden in immersive mode) -->
|
||||
{#if !contactsSettings.immersiveModeEnabled}
|
||||
<!-- Floating/Sidebar Pill Navigation (at bottom) -->
|
||||
|
|
@ -416,7 +351,7 @@
|
|||
showLanguageSwitcher={true}
|
||||
{languageItems}
|
||||
{currentLanguageLabel}
|
||||
showLogout={authStore.isAuthenticated}
|
||||
showLogout={true}
|
||||
onLogout={handleLogout}
|
||||
loginHref="/login"
|
||||
primaryColor="#3b82f6"
|
||||
|
|
@ -482,58 +417,7 @@
|
|||
</div>
|
||||
</SplitPaneContainer>
|
||||
|
||||
<!-- Auth Gate Modal -->
|
||||
<AuthGateModal
|
||||
visible={showAuthGateModal}
|
||||
onClose={() => (showAuthGateModal = false)}
|
||||
onLogin={() => {
|
||||
showAuthGateModal = false;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem('auth-return-url', window.location.pathname);
|
||||
}
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showAuthGateModal = false;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem('auth-return-url', window.location.pathname);
|
||||
}
|
||||
goto('/register');
|
||||
}}
|
||||
action={authGateAction}
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
infoText="Im Demo-Modus werden Beispielkontakte angezeigt. Melde dich an, um eigene Kontakte zu erstellen."
|
||||
/>
|
||||
|
||||
<!-- Guest Welcome Modal -->
|
||||
<GuestWelcomeModal
|
||||
appId="contacts"
|
||||
visible={showGuestWelcome}
|
||||
onClose={() => (showGuestWelcome = false)}
|
||||
onLogin={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/register');
|
||||
}}
|
||||
helpHref="/help"
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
/>
|
||||
|
||||
<style>
|
||||
/* Guest banner styling */
|
||||
.guest-banner {
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
/* Offset content when guest banner is visible */
|
||||
.layout-container:has(.guest-banner) .main-content {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.layout-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
CreatePreview,
|
||||
} from '@manacore/shared-ui';
|
||||
import { getPillAppItems } from '@manacore/shared-branding';
|
||||
import { GuestWelcomeModal, shouldShowGuestWelcome } from '@manacore/shared-auth-ui';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
|
|
@ -41,22 +40,19 @@
|
|||
// User email for nav
|
||||
let userEmail = $derived(authStore.user?.email || 'Menu');
|
||||
|
||||
// Guest welcome modal state
|
||||
let showGuestWelcome = $state(false);
|
||||
|
||||
onMount(async () => {
|
||||
// Set API token if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
const token = await authStore.getValidToken();
|
||||
apiClient.setAccessToken(token);
|
||||
} else {
|
||||
// Show guest welcome modal for unauthenticated users
|
||||
if (shouldShowGuestWelcome('questions')) {
|
||||
showGuestWelcome = true;
|
||||
}
|
||||
// Initialize auth and redirect if not authenticated
|
||||
await authStore.initialize();
|
||||
if (!authStore.isAuthenticated) {
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
// Load initial data (works in both guest and authenticated mode)
|
||||
// Set API token
|
||||
const token = await authStore.getValidToken();
|
||||
apiClient.setAccessToken(token);
|
||||
|
||||
// Load initial data
|
||||
await collectionsStore.load();
|
||||
await questionsStore.load();
|
||||
|
||||
|
|
@ -146,12 +142,6 @@
|
|||
async function handleCreate(query: string): Promise<void> {
|
||||
if (!query.trim()) return;
|
||||
|
||||
// Demo mode: show login prompt
|
||||
if (!authStore.isAuthenticated) {
|
||||
showGuestWelcome = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const question = await questionsStore.create({
|
||||
title: query,
|
||||
collectionId: collectionsStore.selectedId || undefined,
|
||||
|
|
@ -202,54 +192,11 @@
|
|||
{ href: '/collections', label: 'Collections', icon: 'folder' },
|
||||
{ href: '/settings', label: 'Settings', icon: 'settings' },
|
||||
]);
|
||||
|
||||
// Guest features for welcome modal
|
||||
const guestFeatures = [
|
||||
'Browse sample research questions',
|
||||
'Explore the app interface',
|
||||
'See how AI research works',
|
||||
];
|
||||
</script>
|
||||
|
||||
<svelte:window onresize={updateMobileState} />
|
||||
|
||||
<div class="layout-container">
|
||||
<!-- Demo Mode Banner -->
|
||||
{#if !authStore.isAuthenticated}
|
||||
<div
|
||||
class="guest-banner fixed left-0 right-0 top-0 z-50 flex items-center justify-between border-b border-primary/20 bg-primary/10 px-4 py-2"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<svg class="h-4 w-4 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-foreground">
|
||||
<strong>Demo Mode</strong>
|
||||
<span class="hidden text-muted-foreground sm:inline">
|
||||
- Sample questions to explore
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onclick={() => goto('/login')}
|
||||
class="rounded-md bg-primary px-3 py-1 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
|
||||
>
|
||||
Sign In
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Navigation -->
|
||||
<PillNavigation
|
||||
items={navItems}
|
||||
|
|
@ -264,7 +211,7 @@
|
|||
onCollapsedChange={handleCollapsedChange}
|
||||
desktopPosition="bottom"
|
||||
showThemeToggle={true}
|
||||
showLogout={authStore.isAuthenticated}
|
||||
showLogout={true}
|
||||
onLogout={handleSignOut}
|
||||
loginHref="/login"
|
||||
primaryColor="#8b5cf6"
|
||||
|
|
@ -289,35 +236,13 @@
|
|||
/>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main
|
||||
class="main-content bg-background"
|
||||
class:sidebar-mode={isSidebarMode && !isCollapsed}
|
||||
class:has-banner={!authStore.isAuthenticated}
|
||||
>
|
||||
<main class="main-content bg-background" class:sidebar-mode={isSidebarMode && !isCollapsed}>
|
||||
<div class="content-wrapper">
|
||||
{@render children()}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Guest Welcome Modal -->
|
||||
<GuestWelcomeModal
|
||||
appId="questions"
|
||||
visible={showGuestWelcome}
|
||||
onClose={() => (showGuestWelcome = false)}
|
||||
onLogin={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/register');
|
||||
}}
|
||||
helpHref="/help"
|
||||
locale="en"
|
||||
features={guestFeatures}
|
||||
/>
|
||||
|
||||
<style>
|
||||
.layout-container {
|
||||
display: flex;
|
||||
|
|
@ -326,12 +251,6 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Guest banner styling */
|
||||
.guest-banner {
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
|
@ -341,10 +260,6 @@
|
|||
transition: all 300ms ease;
|
||||
}
|
||||
|
||||
.main-content.has-banner {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.main-content.sidebar-mode {
|
||||
padding-left: 180px;
|
||||
padding-bottom: 0;
|
||||
|
|
@ -373,10 +288,6 @@
|
|||
padding-bottom: calc(150px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.main-content.has-banner {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@
|
|||
import { getPillAppItems } from '@manacore/shared-branding';
|
||||
import { getTasks } from '$lib/api/tasks';
|
||||
import { parseTaskInput, resolveTaskIds, formatParsedTaskPreview } from '$lib/utils/task-parser';
|
||||
import {
|
||||
AuthGateModal,
|
||||
GuestWelcomeModal,
|
||||
shouldShowGuestWelcome,
|
||||
} from '@manacore/shared-auth-ui';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// App switcher items
|
||||
const appItems = getPillAppItems('todo');
|
||||
|
|
@ -110,11 +104,6 @@
|
|||
projectId: resolved.projectId,
|
||||
labelIds: resolved.labelIds,
|
||||
});
|
||||
|
||||
// Show auth gate if authentication required (demo mode)
|
||||
if (result && 'error' in result && result.error === 'auth_required') {
|
||||
showAuthGate('save');
|
||||
}
|
||||
}
|
||||
|
||||
let isSidebarMode = $state(false);
|
||||
|
|
@ -279,55 +268,28 @@
|
|||
goto('/login');
|
||||
}
|
||||
|
||||
// Auth gate modal state
|
||||
let showAuthGateModal = $state(false);
|
||||
let authGateAction = $state<'save' | 'sync' | 'feature'>('save');
|
||||
|
||||
// Guest welcome modal state
|
||||
let showGuestWelcome = $state(false);
|
||||
|
||||
// Show auth gate modal (can be called from child components)
|
||||
function showAuthGate(action: 'save' | 'sync' | 'feature' = 'save') {
|
||||
authGateAction = action;
|
||||
showAuthGateModal = true;
|
||||
}
|
||||
|
||||
// Listen for show-auth-gate events from child components
|
||||
$effect(() => {
|
||||
if (browser) {
|
||||
const handler = (e: Event) => {
|
||||
const customEvent = e as CustomEvent<{ action?: 'save' | 'sync' | 'feature' }>;
|
||||
showAuthGate(customEvent.detail?.action || 'save');
|
||||
};
|
||||
window.addEventListener('show-auth-gate', handler);
|
||||
return () => window.removeEventListener('show-auth-gate', handler);
|
||||
}
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
// Initialize auth and redirect if not authenticated
|
||||
await authStore.initialize();
|
||||
if (!authStore.isAuthenticated) {
|
||||
goto('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize split-panel from URL/localStorage
|
||||
splitPanel.initialize();
|
||||
|
||||
// Initialize todo settings
|
||||
todoSettings.initialize();
|
||||
|
||||
// Show guest welcome modal for unauthenticated users
|
||||
if (!authStore.isAuthenticated && shouldShowGuestWelcome('todo')) {
|
||||
showGuestWelcome = true;
|
||||
}
|
||||
|
||||
// Load projects (works in both guest and authenticated mode)
|
||||
// Load projects, labels, and user settings
|
||||
await projectsStore.fetchProjects();
|
||||
await Promise.all([labelsStore.fetchLabels(), userSettings.load()]);
|
||||
|
||||
// Only fetch labels and user settings if authenticated
|
||||
if (authStore.isAuthenticated) {
|
||||
await Promise.all([labelsStore.fetchLabels(), userSettings.load()]);
|
||||
|
||||
// Redirect to start page if on root and a custom start page is set
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath === '/' && userSettings.startPage && userSettings.startPage !== '/') {
|
||||
goto(userSettings.startPage, { replaceState: true });
|
||||
}
|
||||
// Redirect to start page if on root and a custom start page is set
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath === '/' && userSettings.startPage && userSettings.startPage !== '/') {
|
||||
goto(userSettings.startPage, { replaceState: true });
|
||||
}
|
||||
|
||||
// Initialize sidebar mode from localStorage (with error handling for private browsing)
|
||||
|
|
@ -394,41 +356,6 @@
|
|||
|
||||
<SplitPaneContainer>
|
||||
<div class="layout-container">
|
||||
<!-- Demo Mode Banner -->
|
||||
{#if !authStore.isAuthenticated}
|
||||
<div
|
||||
class="guest-banner bg-primary/10 border-primary/20 fixed top-0 right-0 left-0 z-50 flex items-center justify-between border-b px-4 py-2"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<svg class="text-primary h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-foreground">
|
||||
<strong>Demo-Modus</strong>
|
||||
<span class="text-muted-foreground hidden sm:inline">
|
||||
- Beispiel-Aufgaben zum Ausprobieren
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onclick={() => showAuthGate('save')}
|
||||
class="bg-primary text-primary-foreground hover:bg-primary/90 rounded-md px-3 py-1 text-sm font-medium transition-colors"
|
||||
>
|
||||
Anmelden
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- UI Elements (hidden in immersive mode) -->
|
||||
{#if !todoSettings.immersiveModeEnabled}
|
||||
<PillNavigation
|
||||
|
|
@ -452,7 +379,7 @@
|
|||
showLanguageSwitcher={true}
|
||||
{languageItems}
|
||||
{currentLanguageLabel}
|
||||
showLogout={authStore.isAuthenticated}
|
||||
showLogout={true}
|
||||
onLogout={handleLogout}
|
||||
loginHref="/login"
|
||||
primaryColor="#8b5cf6"
|
||||
|
|
@ -514,57 +441,7 @@
|
|||
</div>
|
||||
</SplitPaneContainer>
|
||||
|
||||
<!-- Auth Gate Modal -->
|
||||
<AuthGateModal
|
||||
visible={showAuthGateModal}
|
||||
onClose={() => (showAuthGateModal = false)}
|
||||
onLogin={() => {
|
||||
showAuthGateModal = false;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem('auth-return-url', window.location.pathname);
|
||||
}
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showAuthGateModal = false;
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem('auth-return-url', window.location.pathname);
|
||||
}
|
||||
goto('/register');
|
||||
}}
|
||||
action={authGateAction}
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
infoText="Du kannst die Demo-Aufgaben ansehen, aber um eigene Aufgaben zu erstellen benötigst du ein Konto."
|
||||
/>
|
||||
|
||||
<!-- Guest Welcome Modal -->
|
||||
<GuestWelcomeModal
|
||||
appId="todo"
|
||||
visible={showGuestWelcome}
|
||||
onClose={() => (showGuestWelcome = false)}
|
||||
onLogin={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/login');
|
||||
}}
|
||||
onRegister={() => {
|
||||
showGuestWelcome = false;
|
||||
goto('/register');
|
||||
}}
|
||||
helpHref="/help"
|
||||
locale={currentLocale === 'en' ? 'en' : 'de'}
|
||||
/>
|
||||
|
||||
<style>
|
||||
/* Guest banner styling */
|
||||
.guest-banner {
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
/* Offset content when guest banner is visible */
|
||||
.layout-container:has(.guest-banner) .main-content.floating-mode {
|
||||
padding-top: calc(70px + 40px);
|
||||
}
|
||||
.layout-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue