feat: Add shared components, refactor stores, improve data-entry workflow
Shared Components: - Add CompanySelector.vue and PeriodSelector.vue components - Add AppHeader.vue and SlideMenu.vue layout components - Add shared stores factories (companies.js, accountingPeriod.js) - Add shared routes factories (companies.py, calendar.py) - Add shared models (company.py, calendar.py) - Add shared layout styles (header.css, navigation.css) Data Entry App: - Update CLAUDE.md with prod/test server documentation - Improve nomenclature sync service with better error handling - Update receipts router and CRUD operations - Add company/period stores using shared factories - Update App.vue layout with shared components - Fix OCRUploadZone file handling Reports App: - Refactor stores to use shared factories - Update App.vue to use shared layout components Infrastructure: - Replace start-data-entry.sh with separate dev/test scripts - Add .claude/rules for authentication, backend patterns, etc. - Add implementation plan for OCR receipt improvements - Clean up old documentation files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,25 +1,79 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<!-- New Navigation System -->
|
||||
<DashboardHeader
|
||||
<!-- Shared Header Component -->
|
||||
<AppHeader
|
||||
v-if="authStore.isAuthenticated"
|
||||
title="ROA2WEB"
|
||||
brand-link="/dashboard"
|
||||
:menu-open="menuOpen"
|
||||
@menu-toggle="handleMenuToggle"
|
||||
:companies-store="companyStore"
|
||||
:period-store="periodStore"
|
||||
:current-user="authStore.currentUser"
|
||||
:show-user="true"
|
||||
@menu-toggle="menuOpen = !menuOpen"
|
||||
@company-changed="handleCompanyChanged"
|
||||
/>
|
||||
@period-changed="handlePeriodChanged"
|
||||
@user-menu-toggle="handleUserMenuToggle"
|
||||
>
|
||||
<template #user-menu>
|
||||
<div class="user-menu-container mobile-hide">
|
||||
<div class="header-user" @click="toggleUserMenu">
|
||||
<i class="pi pi-user"></i>
|
||||
<span class="desktop-only">{{ authStore.currentUser?.username || "User" }}</span>
|
||||
<i class="pi pi-chevron-down" :class="{ 'rotate-180': userMenuOpen }"></i>
|
||||
</div>
|
||||
|
||||
<!-- Hamburger Menu -->
|
||||
<HamburgerMenu
|
||||
<!-- User Dropdown Menu -->
|
||||
<div v-if="userMenuOpen" class="user-dropdown">
|
||||
<div class="user-dropdown-header">
|
||||
<div class="user-info">
|
||||
<div class="user-name">{{ authStore.currentUser?.username || "User" }}</div>
|
||||
<div class="user-email">{{ authStore.currentUser?.email || "" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-dropdown-divider"></div>
|
||||
<button class="user-dropdown-item" @click="navigateToTelegram">
|
||||
<i class="pi pi-telegram"></i>
|
||||
<span>Telegram Bot</span>
|
||||
</button>
|
||||
<div class="user-dropdown-divider"></div>
|
||||
<button class="user-dropdown-item" @click="handleLogout">
|
||||
<i class="pi pi-sign-out"></i>
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</AppHeader>
|
||||
|
||||
<!-- Shared Slide Menu -->
|
||||
<SlideMenu
|
||||
v-if="authStore.isAuthenticated"
|
||||
:is-open="menuOpen"
|
||||
@close="handleMenuClose"
|
||||
/>
|
||||
:menu-items="reportsMenuItems"
|
||||
:current-user="authStore.currentUser"
|
||||
@close="menuOpen = false"
|
||||
@logout="handleLogout"
|
||||
>
|
||||
<template #profile-items>
|
||||
<li class="menu-item">
|
||||
<router-link
|
||||
to="/telegram"
|
||||
class="menu-link"
|
||||
@click="menuOpen = false"
|
||||
>
|
||||
<i class="menu-icon pi pi-telegram"></i>
|
||||
<span>Telegram Bot</span>
|
||||
</router-link>
|
||||
</li>
|
||||
</template>
|
||||
</SlideMenu>
|
||||
|
||||
<!-- User Menu Overlay -->
|
||||
<div v-if="userMenuOpen" class="user-menu-overlay" @click="closeUserMenu"></div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main
|
||||
class="main-content"
|
||||
:class="{ 'with-navbar': authStore.isAuthenticated }"
|
||||
>
|
||||
<main class="main-content" :class="{ 'with-navbar': authStore.isAuthenticated }">
|
||||
<router-view />
|
||||
</main>
|
||||
|
||||
@@ -36,24 +90,49 @@ import { ref, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useAuthStore } from "./stores/auth";
|
||||
import { useCompanyStore } from "./stores/companies";
|
||||
import DashboardHeader from "./components/layout/DashboardHeader.vue";
|
||||
import HamburgerMenu from "./components/layout/HamburgerMenu.vue";
|
||||
import { useAccountingPeriodStore } from "./stores/accountingPeriod";
|
||||
import AppHeader from "../../../shared/frontend/components/layout/AppHeader.vue";
|
||||
import SlideMenu from "../../../shared/frontend/components/layout/SlideMenu.vue";
|
||||
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const companyStore = useCompanyStore();
|
||||
const periodStore = useAccountingPeriodStore();
|
||||
|
||||
// Menu state
|
||||
const menuOpen = ref(false);
|
||||
const userMenuOpen = ref(false);
|
||||
|
||||
// Handle menu toggle
|
||||
const handleMenuToggle = () => {
|
||||
menuOpen.value = !menuOpen.value;
|
||||
// Menu items configuration for reports-app
|
||||
const reportsMenuItems = [
|
||||
{
|
||||
title: 'Navigare',
|
||||
items: [
|
||||
{ to: '/dashboard', icon: 'pi pi-home', label: 'Dashboard' },
|
||||
{ to: '/invoices', icon: 'pi pi-file', label: 'Facturi' },
|
||||
{ to: '/bank-cash-register', icon: 'pi pi-money-bill', label: 'Casa și Banca' },
|
||||
{ to: '/trial-balance', icon: 'pi pi-calculator', label: 'Balanță de Verificare' },
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Sistem',
|
||||
items: [
|
||||
{ to: '/cache-stats', icon: 'pi pi-chart-bar', label: 'Statistici cache' },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// User menu handlers
|
||||
const toggleUserMenu = () => {
|
||||
userMenuOpen.value = !userMenuOpen.value;
|
||||
};
|
||||
|
||||
// Handle menu close
|
||||
const handleMenuClose = () => {
|
||||
menuOpen.value = false;
|
||||
const closeUserMenu = () => {
|
||||
userMenuOpen.value = false;
|
||||
};
|
||||
|
||||
const handleUserMenuToggle = () => {
|
||||
toggleUserMenu();
|
||||
};
|
||||
|
||||
// Handle company change
|
||||
@@ -61,6 +140,35 @@ const handleCompanyChanged = (company) => {
|
||||
console.log("Company changed in App:", company);
|
||||
};
|
||||
|
||||
// Handle period change
|
||||
const handlePeriodChanged = (period) => {
|
||||
console.log("Period changed in App:", period);
|
||||
};
|
||||
|
||||
// Navigate to Telegram
|
||||
const navigateToTelegram = async () => {
|
||||
try {
|
||||
closeUserMenu();
|
||||
await router.push("/telegram");
|
||||
} catch (error) {
|
||||
console.error("Navigation error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle logout
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
authStore.logout();
|
||||
companyStore.reset();
|
||||
periodStore.reset();
|
||||
closeUserMenu();
|
||||
menuOpen.value = false;
|
||||
await router.push("/login");
|
||||
} catch (error) {
|
||||
console.error("Logout error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize app
|
||||
onMounted(async () => {
|
||||
// Check authentication on app start
|
||||
@@ -93,6 +201,146 @@ onMounted(async () => {
|
||||
.main-content:not(.with-navbar) {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* User Menu Container */
|
||||
.user-menu-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Header User Button */
|
||||
.header-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--color-primary);
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-md);
|
||||
transition: background-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.header-user:hover {
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
/* User Dropdown */
|
||||
.user-dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
min-width: 220px;
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-lg);
|
||||
z-index: var(--z-dropdown, 1000);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.user-dropdown-header {
|
||||
padding: var(--space-md);
|
||||
background: var(--color-bg-secondary);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--color-text);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.user-email {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.user-dropdown-divider {
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
.user-dropdown-item {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-text);
|
||||
font-size: var(--text-sm);
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: background-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.user-dropdown-item:hover {
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
.user-dropdown-item:focus {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: -2px;
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
/* User Menu Overlay */
|
||||
.user-menu-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Chevron rotation animation */
|
||||
.rotate-180 {
|
||||
transform: rotate(180deg);
|
||||
transition: transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.pi-chevron-down {
|
||||
transition: transform var(--transition-fast);
|
||||
}
|
||||
|
||||
/* Desktop only class */
|
||||
.desktop-only {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.user-dropdown {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.user-dropdown-header {
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.user-dropdown-item {
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
/* Hide profile menu on mobile - use hamburger menu instead */
|
||||
.mobile-hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
/* Import order is critical for proper CSS cascade */
|
||||
|
||||
/* 0. Shared Layout Styles (from shared/frontend/styles) */
|
||||
@import '../../../../../shared/frontend/styles/layout/header.css';
|
||||
@import '../../../../../shared/frontend/styles/layout/navigation.css';
|
||||
|
||||
/* 1. Core Foundation */
|
||||
@import "./core/variables.css";
|
||||
@import "./core/tokens.css"; /* NEW - Extended design tokens */
|
||||
|
||||
@@ -1,138 +1,17 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref, computed } from "vue";
|
||||
/**
|
||||
* Accounting Period Store for Reports App
|
||||
*
|
||||
* Uses the shared accounting period store factory from shared/frontend/stores/accountingPeriod.js
|
||||
* Configured with the reports API service (port 8001)
|
||||
*/
|
||||
|
||||
import { createAccountingPeriodStore } from "@shared/frontend/stores/accountingPeriod";
|
||||
import { apiService } from "../services/api";
|
||||
import { useAuthStore } from "./auth";
|
||||
import { useCompanyStore } from "./companies";
|
||||
|
||||
export const useAccountingPeriodStore = defineStore("accountingPeriod", () => {
|
||||
// State
|
||||
const periods = ref([]);
|
||||
const selectedPeriod = ref(null);
|
||||
const isLoading = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
// Getters
|
||||
const hasPeriods = computed(() => periods.value.length > 0);
|
||||
const currentPeriod = computed(() => selectedPeriod.value);
|
||||
|
||||
// Computed date range for current period (first/last day of month)
|
||||
const dateRange = computed(() => {
|
||||
if (!selectedPeriod.value) return { dateFrom: null, dateTo: null };
|
||||
|
||||
const { an, luna } = selectedPeriod.value;
|
||||
const firstDay = new Date(an, luna - 1, 1);
|
||||
const lastDay = new Date(an, luna, 0);
|
||||
|
||||
return {
|
||||
dateFrom: firstDay,
|
||||
dateTo: lastDay,
|
||||
};
|
||||
});
|
||||
|
||||
// Actions
|
||||
const loadPeriods = async (companyId) => {
|
||||
if (!companyId) return { success: false };
|
||||
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await apiService.get("/calendar/periods", {
|
||||
params: { company: companyId },
|
||||
});
|
||||
|
||||
periods.value = response.data.periods || [];
|
||||
|
||||
// Try to restore saved period or use most recent
|
||||
const saved = initializeSelectedPeriod();
|
||||
if (saved) {
|
||||
const exists = periods.value.find(
|
||||
(p) => p.an === saved.an && p.luna === saved.luna
|
||||
);
|
||||
if (exists) {
|
||||
selectedPeriod.value = exists;
|
||||
} else if (response.data.current_period) {
|
||||
setSelectedPeriod(response.data.current_period);
|
||||
}
|
||||
} else if (response.data.current_period) {
|
||||
setSelectedPeriod(response.data.current_period);
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.detail || "Failed to load periods";
|
||||
return { success: false, error: error.value };
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const setSelectedPeriod = (period) => {
|
||||
selectedPeriod.value = period;
|
||||
persistSelectedPeriod(period);
|
||||
};
|
||||
|
||||
const resetToLatest = () => {
|
||||
if (periods.value.length > 0) {
|
||||
setSelectedPeriod(periods.value[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
periods.value = [];
|
||||
selectedPeriod.value = null;
|
||||
isLoading.value = false;
|
||||
error.value = null;
|
||||
};
|
||||
|
||||
// localStorage helpers
|
||||
const getStorageKey = () => {
|
||||
const authStore = useAuthStore();
|
||||
const companyStore = useCompanyStore();
|
||||
const username = authStore.user?.username;
|
||||
const companyId = companyStore.selectedCompany?.id_firma;
|
||||
if (!username || !companyId) return null;
|
||||
return `selected_period_${username}_${companyId}`;
|
||||
};
|
||||
|
||||
const initializeSelectedPeriod = () => {
|
||||
const key = getStorageKey();
|
||||
if (!key) return null;
|
||||
|
||||
const saved = localStorage.getItem(key);
|
||||
if (saved) {
|
||||
try {
|
||||
return JSON.parse(saved);
|
||||
} catch (e) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const persistSelectedPeriod = (period) => {
|
||||
const key = getStorageKey();
|
||||
if (key && period) {
|
||||
localStorage.setItem(key, JSON.stringify(period));
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
periods,
|
||||
selectedPeriod,
|
||||
isLoading,
|
||||
error,
|
||||
|
||||
// Getters
|
||||
hasPeriods,
|
||||
currentPeriod,
|
||||
dateRange,
|
||||
|
||||
// Actions
|
||||
loadPeriods,
|
||||
setSelectedPeriod,
|
||||
resetToLatest,
|
||||
reset,
|
||||
};
|
||||
});
|
||||
export const useAccountingPeriodStore = createAccountingPeriodStore(
|
||||
apiService,
|
||||
useAuthStore,
|
||||
useCompanyStore
|
||||
);
|
||||
|
||||
@@ -1,205 +1,12 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref, computed, watch } from "vue";
|
||||
/**
|
||||
* Companies Store for Reports App
|
||||
*
|
||||
* Uses the shared companies store factory from shared/frontend/stores/companies.js
|
||||
* Configured with the reports API service (port 8001)
|
||||
*/
|
||||
|
||||
import { createCompaniesStore } from "@shared/frontend/stores/companies";
|
||||
import { apiService } from "../services/api";
|
||||
import { useAuthStore } from "./auth";
|
||||
|
||||
export const useCompanyStore = defineStore("companies", () => {
|
||||
// Initialize from localStorage - per user
|
||||
const initializeSelectedCompany = () => {
|
||||
// Get current username from auth store
|
||||
const authStore = useAuthStore();
|
||||
const username = authStore.user?.username;
|
||||
|
||||
if (!username) {
|
||||
console.log("[Companies] No username available for initialization");
|
||||
return null;
|
||||
}
|
||||
|
||||
const key = `selected_company_${username}`;
|
||||
const saved = localStorage.getItem(key);
|
||||
if (saved) {
|
||||
try {
|
||||
const company = JSON.parse(saved);
|
||||
console.log(
|
||||
`[Companies] Loaded saved company for user ${username}:`,
|
||||
company.name,
|
||||
);
|
||||
return company;
|
||||
} catch (e) {
|
||||
console.error("Failed to parse saved company", e);
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// State
|
||||
const companies = ref([]);
|
||||
const selectedCompany = ref(initializeSelectedCompany());
|
||||
const isLoading = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
// Watch for auth user changes to restore selected company
|
||||
const authStore = useAuthStore();
|
||||
watch(
|
||||
() => authStore.user,
|
||||
(newUser) => {
|
||||
if (newUser && newUser.username && !selectedCompany.value) {
|
||||
console.log(
|
||||
"[Companies] User became available, attempting to restore selected company",
|
||||
);
|
||||
const restoredCompany = initializeSelectedCompany();
|
||||
if (restoredCompany) {
|
||||
selectedCompany.value = restoredCompany;
|
||||
console.log(
|
||||
"[Companies] Successfully restored selected company:",
|
||||
restoredCompany.name,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// Getters
|
||||
const companyList = computed(() => companies.value);
|
||||
const hasCompanies = computed(() => companies.value.length > 0);
|
||||
const selectedCompanyId = computed(
|
||||
() => selectedCompany.value?.id_firma || null,
|
||||
);
|
||||
|
||||
// Computed property for formatted company list display
|
||||
const companyListFormatted = computed(() => {
|
||||
return companies.value.map((company) => ({
|
||||
...company,
|
||||
displayName: company.fiscal_code
|
||||
? `${company.name} (${company.fiscal_code})`
|
||||
: company.name,
|
||||
}));
|
||||
});
|
||||
|
||||
// Actions
|
||||
const loadCompanies = async () => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
console.log("[COMPANY STORE DEBUG] Loading companies...");
|
||||
const response = await apiService.get("/companies");
|
||||
console.log("[COMPANY STORE DEBUG] API Response:", response.data);
|
||||
companies.value = response.data.companies || [];
|
||||
console.log("[COMPANY STORE DEBUG] Companies array:", companies.value);
|
||||
|
||||
// Security validation: Check if saved company is accessible to current user
|
||||
if (selectedCompany.value) {
|
||||
const exists = companies.value.find(
|
||||
(c) => c.id_firma === selectedCompany.value.id_firma,
|
||||
);
|
||||
if (!exists) {
|
||||
console.warn(
|
||||
"[Companies][Security] Saved company not accessible to current user, clearing",
|
||||
);
|
||||
clearSelectedCompany();
|
||||
} else {
|
||||
console.log(
|
||||
"[Companies][Security] Saved company validated successfully",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.detail || "Failed to load companies";
|
||||
console.error("Failed to load companies:", err);
|
||||
return { success: false, error: error.value };
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const setSelectedCompany = (company) => {
|
||||
selectedCompany.value = company;
|
||||
|
||||
// Get current username from auth store
|
||||
const authStore = useAuthStore();
|
||||
const username = authStore.user?.username;
|
||||
|
||||
if (!username) {
|
||||
console.warn("[Companies] Cannot save company - no username available");
|
||||
return;
|
||||
}
|
||||
|
||||
const key = `selected_company_${username}`;
|
||||
if (company) {
|
||||
localStorage.setItem(key, JSON.stringify(company));
|
||||
console.log(
|
||||
`[Companies] Saved company for user ${username}:`,
|
||||
company.name,
|
||||
);
|
||||
} else {
|
||||
localStorage.removeItem(key);
|
||||
console.log(`[Companies] Cleared company for user ${username}`);
|
||||
}
|
||||
};
|
||||
|
||||
const clearSelectedCompany = () => {
|
||||
selectedCompany.value = null;
|
||||
|
||||
// Get current username from auth store
|
||||
const authStore = useAuthStore();
|
||||
const username = authStore.user?.username;
|
||||
|
||||
if (username) {
|
||||
const key = `selected_company_${username}`;
|
||||
localStorage.removeItem(key);
|
||||
console.log(`[Companies] Cleared company for user ${username}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getCompanyById = (id_firma) => {
|
||||
return companies.value.find(
|
||||
(company) => company.id_firma === parseInt(id_firma),
|
||||
);
|
||||
};
|
||||
|
||||
const clearError = () => {
|
||||
error.value = null;
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
companies.value = [];
|
||||
selectedCompany.value = null;
|
||||
isLoading.value = false;
|
||||
error.value = null;
|
||||
|
||||
// Clear saved company for current user
|
||||
const authStore = useAuthStore();
|
||||
const username = authStore.user?.username;
|
||||
if (username) {
|
||||
const key = `selected_company_${username}`;
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
companies,
|
||||
selectedCompany,
|
||||
isLoading,
|
||||
error,
|
||||
|
||||
// Getters
|
||||
companyList,
|
||||
companyListFormatted,
|
||||
hasCompanies,
|
||||
selectedCompanyId,
|
||||
|
||||
// Actions
|
||||
loadCompanies,
|
||||
setSelectedCompany,
|
||||
clearSelectedCompany,
|
||||
getCompanyById,
|
||||
clearError,
|
||||
reset,
|
||||
};
|
||||
});
|
||||
export const useCompanyStore = createCompaniesStore(apiService, useAuthStore);
|
||||
|
||||
Reference in New Issue
Block a user