fix: React 프론트엔드 버그 수정 및 모바일 반응형 개선

- CORS: React 포트(5174) 허용 추가 (application.yml)
- ProjectController: /my 엔드포인트 userId 파라미터 선택사항으로 변경
- API 응답 안전 처리: toArray 유틸 추가, 모든 뷰에서 배열 보장
- DataTable emptyMessage: JSX → 문자열로 변경 (PrimeReact 호환)
- LoginView: Password → InputText type=password 변경
- 모바일 사이드바: Vue/React 양쪽 inline width 제거로 슬라이드 정상 동작
- 모바일 서브메뉴 텍스트 표시 CSS 수정

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
이 Commit은 다음에 포함되어 있습니다:
2026-03-30 21:35:53 +09:00
부모 cda5f9591e
커밋 85aaebe134
18개의 변경된 파일90개의 추가작업 그리고 42개의 파일을 삭제

파일 보기

@@ -8,6 +8,8 @@ import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import kr.co.accura.wbx.spring.auth.WbxUserDetails;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -45,8 +47,11 @@ public class ProjectController {
} }
@GetMapping("/my") @GetMapping("/my")
public ResponseEntity<List<ProjectDto>> myProjects(@RequestParam Long userId) { public ResponseEntity<List<ProjectDto>> myProjects(
return ResponseEntity.ok(projectService.findMyProjects(userId)); @AuthenticationPrincipal WbxUserDetails user,
@RequestParam(required = false) Long userId) {
Long resolvedUserId = userId != null ? userId : user.getId();
return ResponseEntity.ok(projectService.findMyProjects(resolvedUserId));
} }
@GetMapping("/{id}/members") @GetMapping("/{id}/members")

파일 보기

@@ -36,7 +36,7 @@ wbx:
admin-ui: admin-ui:
enabled: true enabled: true
cors: cors:
allowed-origins: ${CORS_ORIGINS:http://localhost:5173} allowed-origins: ${CORS_ORIGINS:http://localhost:5173,http://localhost:5174}
notification: notification:
sse-enabled: true sse-enabled: true

파일 보기

@@ -0,0 +1,14 @@
/**
* API 응답에서 안전하게 배열을 추출합니다.
* - 응답이 배열이면 그대로 반환
* - 응답이 { items: [...] } 형태면 items 반환
* - 그 외 빈 배열 반환
*/
export function toArray<T>(data: unknown): T[] {
if (Array.isArray(data)) return data as T[];
if (data && typeof data === 'object' && 'items' in data) {
const items = (data as Record<string, unknown>).items;
if (Array.isArray(items)) return items as T[];
}
return [];
}

파일 보기

@@ -59,4 +59,28 @@
border: none; border: none;
background: transparent; background: transparent;
} }
&__menu .p-panelmenu-panel {
.p-panelmenu-header-content,
.p-menuitem-content {
white-space: nowrap;
overflow: visible;
}
.p-panelmenu-content {
overflow: visible;
}
.p-menuitem-text {
display: inline !important;
}
}
// 모바일에서 서브메뉴 텍스트 표시 보장
&--mobile &__nav {
.p-menuitem-text,
.p-panelmenu-header-content span {
display: inline !important;
}
}
} }

파일 보기

@@ -34,8 +34,6 @@ export default function AppSidebar({ visible, collapsed, mobile }: Props) {
})); }));
}, [currentUser, navigate]); }, [currentUser, navigate]);
const sidebarWidth = collapsed ? `${LAYOUT.sidebarCollapsedWidth}px` : `${LAYOUT.sidebarWidth}px`;
const classNames = [ const classNames = [
'app-sidebar', 'app-sidebar',
visible && 'app-sidebar--visible', visible && 'app-sidebar--visible',
@@ -45,8 +43,12 @@ export default function AppSidebar({ visible, collapsed, mobile }: Props) {
.filter(Boolean) .filter(Boolean)
.join(' '); .join(' ');
const style = mobile
? undefined
: { width: collapsed ? `${LAYOUT.sidebarCollapsedWidth}px` : `${LAYOUT.sidebarWidth}px` };
return ( return (
<aside className={classNames} style={{ width: sidebarWidth }}> <aside className={classNames} style={style}>
<div className="app-sidebar__header"> <div className="app-sidebar__header">
<img src={logo} alt="WTM" className="app-sidebar__logo" /> <img src={logo} alt="WTM" className="app-sidebar__logo" />
{!collapsed && <span className="app-sidebar__title">WTM</span>} {!collapsed && <span className="app-sidebar__title">WTM</span>}

파일 보기

@@ -77,12 +77,7 @@ export default function BaseCrudTable<T extends Record<string, any>>({
className="crud-table__datatable" className="crud-table__datatable"
onRowSelect={(e) => onRowSelect?.(e.data as T)} onRowSelect={(e) => onRowSelect?.(e.data as T)}
onPage={onPage} onPage={onPage}
emptyMessage={ emptyMessage={emptyMessage}
<div className="crud-table__empty">
<i className="pi pi-inbox" style={{ fontSize: '2rem' }} />
<p>{emptyMessage}</p>
</div>
}
> >
{children} {children}
</DataTable> </DataTable>

파일 보기

@@ -7,6 +7,7 @@ import BaseCrudTable from '@/core/components/BaseCrudTable';
import BasePageHeader from '@/core/components/BasePageHeader'; import BasePageHeader from '@/core/components/BasePageHeader';
import { approvalService } from '../approval.service'; import { approvalService } from '../approval.service';
import { TIMESHEET_STATUS } from '@/core/constants/app.constants'; import { TIMESHEET_STATUS } from '@/core/constants/app.constants';
import { toArray } from '@/core/api/utils';
export default function ApprovalHistoryView() { export default function ApprovalHistoryView() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -23,7 +24,7 @@ export default function ApprovalHistoryView() {
if (dateTo) params.to = dateTo.toISOString().slice(0, 10); if (dateTo) params.to = dateTo.toISOString().slice(0, 10);
approvalService.getHistory(params) approvalService.getHistory(params)
.then(({ data }) => setHistory((data as { items?: unknown[] }).items as Record<string, unknown>[] ?? data as Record<string, unknown>[])) .then(({ data }) => setHistory(toArray<Record<string, unknown>>(data)))
.catch(() => setHistory([])) .catch(() => setHistory([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}, [statusFilter, dateFrom, dateTo]); }, [statusFilter, dateFrom, dateTo]);

파일 보기

@@ -7,6 +7,7 @@ import BasePageHeader from '@/core/components/BasePageHeader';
import { approvalService } from '../approval.service'; import { approvalService } from '../approval.service';
import { TIMESHEET_STATUS } from '@/core/constants/app.constants'; import { TIMESHEET_STATUS } from '@/core/constants/app.constants';
import type { Approval } from '../approval.types'; import type { Approval } from '../approval.types';
import { toArray } from '@/core/api/utils';
export default function ApprovalPendingView() { export default function ApprovalPendingView() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -16,7 +17,7 @@ export default function ApprovalPendingView() {
function load() { function load() {
setLoading(true); setLoading(true);
approvalService.getPending() approvalService.getPending()
.then(({ data }) => setApprovals((data as { items?: Approval[] }).items ?? data as Approval[])) .then(({ data }) => setApprovals(toArray<Approval>(data)))
.catch(() => setApprovals([])) .catch(() => setApprovals([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }

파일 보기

@@ -1,7 +1,6 @@
import { useState, type FormEvent } from 'react'; import { useState, type FormEvent } from 'react';
import { useNavigate, Link } from 'react-router-dom'; import { useNavigate, Link } from 'react-router-dom';
import { InputText } from 'primereact/inputtext'; import { InputText } from 'primereact/inputtext';
import { Password } from 'primereact/password';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { Card } from 'primereact/card'; import { Card } from 'primereact/card';
import { Message } from 'primereact/message'; import { Message } from 'primereact/message';
@@ -55,13 +54,11 @@ export default function LoginView() {
<div className="form-field"> <div className="form-field">
<label className="form-field__label"></label> <label className="form-field__label"></label>
<Password <InputText
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
type="password"
placeholder="비밀번호 입력" placeholder="비밀번호 입력"
feedback={false}
toggleMask
inputStyle={{ width: '100%' }}
/> />
</div> </div>

파일 보기

@@ -39,14 +39,16 @@ export default function DashboardView() {
setLoading(true); setLoading(true);
dashboardService.getDashboard() dashboardService.getDashboard()
.then(({ data }) => { .then(({ data }) => {
setStats(data.stats ?? defaultStats); const d = data as Record<string, unknown>;
setPendingApprovals(data.pendingApprovals ?? []); setStats(Array.isArray(d.stats) ? d.stats as DashboardStat[] : defaultStats);
setPendingApprovals(Array.isArray(d.pendingApprovals) ? d.pendingApprovals as Record<string, unknown>[]
: Array.isArray(d.recentTimesheets) ? d.recentTimesheets as Record<string, unknown>[] : []);
setWeeklyHoursData({ setWeeklyHoursData({
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
datasets: [{ datasets: [{
label: '시수', label: '시수',
backgroundColor: 'var(--p-primary-color)', backgroundColor: '#3B82F6',
data: data.weeklyHours ?? [0, 0, 0, 0, 0, 0], data: Array.isArray(d.weeklyHours) ? d.weeklyHours : [0, 0, 0, 0, 0, 0],
}], }],
}); });
}) })
@@ -54,7 +56,7 @@ export default function DashboardView() {
setStats(defaultStats); setStats(defaultStats);
setWeeklyHoursData({ setWeeklyHoursData({
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
datasets: [{ label: '시수', backgroundColor: 'var(--p-primary-color)', data: [0, 0, 0, 0, 0, 0] }], datasets: [{ label: '시수', backgroundColor: '#3B82F6', data: [0, 0, 0, 0, 0, 0] }],
}); });
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
@@ -109,7 +111,7 @@ export default function DashboardView() {
<Card title="결재 대기 목록" className="dashboard-view__approvals-card"> <Card title="결재 대기 목록" className="dashboard-view__approvals-card">
<DataTable value={pendingApprovals} rows={5} paginator={pendingApprovals.length > 5} size="small" stripedRows <DataTable value={pendingApprovals} rows={5} paginator={pendingApprovals.length > 5} size="small" stripedRows
emptyMessage={<div style={{ textAlign: 'center', padding: '1rem', color: 'var(--p-text-muted-color)' }}> .</div>} emptyMessage="결재 대기 건이 없습니다."
> >
<Column field="requesterName" header="요청자" /> <Column field="requesterName" header="요청자" />
<Column field="projectName" header="프로젝트" /> <Column field="projectName" header="프로젝트" />

파일 보기

@@ -9,6 +9,7 @@ import ProjectFormDialog from '../components/ProjectFormDialog';
import { projectService } from '../project.service'; import { projectService } from '../project.service';
import { PROJECT_STATUS } from '@/core/constants/app.constants'; import { PROJECT_STATUS } from '@/core/constants/app.constants';
import type { Project } from '../project.types'; import type { Project } from '../project.types';
import { toArray } from '@/core/api/utils';
export default function ProjectListView() { export default function ProjectListView() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -20,7 +21,7 @@ export default function ProjectListView() {
function load() { function load() {
setLoading(true); setLoading(true);
projectService.getAll() projectService.getAll()
.then(({ data }) => setProjects((data as { items?: Project[] }).items ?? data as Project[])) .then(({ data }) => setProjects(toArray<Project>(data)))
.catch(() => setProjects([])) .catch(() => setProjects([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }

파일 보기

@@ -9,6 +9,7 @@ import { Chart } from 'primereact/chart';
import BasePageHeader from '@/core/components/BasePageHeader'; import BasePageHeader from '@/core/components/BasePageHeader';
import { reportService } from '../report.service'; import { reportService } from '../report.service';
import { projectService } from '@/modules/project/project.service'; import { projectService } from '@/modules/project/project.service';
import { toArray } from '@/core/api/utils';
export default function ReportView() { export default function ReportView() {
const [projects, setProjects] = useState<{ id: number; name: string }[]>([]); const [projects, setProjects] = useState<{ id: number; name: string }[]>([]);
@@ -28,7 +29,7 @@ export default function ReportView() {
useEffect(() => { useEffect(() => {
projectService.getAll() projectService.getAll()
.then(({ data }) => setProjects((data as { items?: unknown[] }).items as { id: number; name: string }[] ?? data as { id: number; name: string }[])) .then(({ data }) => setProjects(toArray<{ id: number; name: string }>(data)))
.catch(() => setProjects([])); .catch(() => setProjects([]));
}, []); }, []);
@@ -40,7 +41,7 @@ export default function ReportView() {
if (dateTo) params.to = dateTo.toISOString().slice(0, 10); if (dateTo) params.to = dateTo.toISOString().slice(0, 10);
reportService.getProjectHours(params) reportService.getProjectHours(params)
.then(({ data }) => setData(Array.isArray(data) ? data : (data as { items?: unknown[] }).items as Record<string, unknown>[] ?? [])) .then(({ data }) => setData(toArray<Record<string, unknown>>(data)))
.catch(() => setData([])) .catch(() => setData([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }

파일 보기

@@ -9,6 +9,7 @@ import TealUploadDialog from '../components/TealUploadDialog';
import { tealService } from '../teal.service'; import { tealService } from '../teal.service';
import { projectService } from '@/modules/project/project.service'; import { projectService } from '@/modules/project/project.service';
import type { TealEntry, TealVersion } from '../teal.types'; import type { TealEntry, TealVersion } from '../teal.types';
import { toArray } from '@/core/api/utils';
export default function TealListView() { export default function TealListView() {
const [projects, setProjects] = useState<{ id: number; name: string; code: string }[]>([]); const [projects, setProjects] = useState<{ id: number; name: string; code: string }[]>([]);
@@ -21,14 +22,14 @@ export default function TealListView() {
useEffect(() => { useEffect(() => {
projectService.getAll() projectService.getAll()
.then(({ data }) => setProjects((data as { items?: unknown[] }).items as { id: number; name: string; code: string }[] ?? data as { id: number; name: string; code: string }[])) .then(({ data }) => setProjects(toArray<{ id: number; name: string; code: string }>(data)))
.catch(() => setProjects([])); .catch(() => setProjects([]));
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!selectedProjectId) { setVersions([]); setEntries([]); return; } if (!selectedProjectId) { setVersions([]); setEntries([]); return; }
tealService.getVersions(selectedProjectId) tealService.getVersions(selectedProjectId)
.then(({ data }) => setVersions(data as TealVersion[])) .then(({ data }) => setVersions(toArray<TealVersion>(data)))
.catch(() => setVersions([])); .catch(() => setVersions([]));
}, [selectedProjectId]); }, [selectedProjectId]);
@@ -36,7 +37,7 @@ export default function TealListView() {
if (!selectedProjectId || !selectedVersionId) { setEntries([]); return; } if (!selectedProjectId || !selectedVersionId) { setEntries([]); return; }
setLoading(true); setLoading(true);
tealService.getActive(selectedProjectId) tealService.getActive(selectedProjectId)
.then(({ data }) => setEntries(data as TealEntry[])) .then(({ data }) => setEntries(toArray<TealEntry>(data)))
.catch(() => setEntries([])) .catch(() => setEntries([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}, [selectedProjectId, selectedVersionId]); }, [selectedProjectId, selectedVersionId]);
@@ -46,7 +47,7 @@ export default function TealListView() {
await tealService.upload(selectedProjectId, file, effectiveDate); await tealService.upload(selectedProjectId, file, effectiveDate);
setUploadVisible(false); setUploadVisible(false);
const { data } = await tealService.getVersions(selectedProjectId); const { data } = await tealService.getVersions(selectedProjectId);
setVersions(data as TealVersion[]); setVersions(toArray<TealVersion>(data));
} }
return ( return (

파일 보기

@@ -8,6 +8,7 @@ import BaseCrudTable from '@/core/components/BaseCrudTable';
import BasePageHeader from '@/core/components/BasePageHeader'; import BasePageHeader from '@/core/components/BasePageHeader';
import { timesheetService } from '../timesheet.service'; import { timesheetService } from '../timesheet.service';
import { TIMESHEET_STATUS } from '@/core/constants/app.constants'; import { TIMESHEET_STATUS } from '@/core/constants/app.constants';
import { toArray } from '@/core/api/utils';
export default function TimesheetHistoryView() { export default function TimesheetHistoryView() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -25,7 +26,7 @@ export default function TimesheetHistoryView() {
if (dateTo) params.to = dateTo.toISOString().slice(0, 10); if (dateTo) params.to = dateTo.toISOString().slice(0, 10);
timesheetService.getHistory(params) timesheetService.getHistory(params)
.then(({ data }) => setHistory((data as { items?: unknown[] }).items as Record<string, unknown>[] ?? data as Record<string, unknown>[])) .then(({ data }) => setHistory(toArray<Record<string, unknown>>(data)))
.catch(() => setHistory([])) .catch(() => setHistory([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}, [statusFilter, dateFrom, dateTo]); }, [statusFilter, dateFrom, dateTo]);

파일 보기

@@ -10,6 +10,7 @@ import BasePageHeader from '@/core/components/BasePageHeader';
import TimesheetEntryRow from '../components/TimesheetEntryRow'; import TimesheetEntryRow from '../components/TimesheetEntryRow';
import { timesheetService } from '../timesheet.service'; import { timesheetService } from '../timesheet.service';
import { projectService } from '@/modules/project/project.service'; import { projectService } from '@/modules/project/project.service';
import { toArray } from '@/core/api/utils';
import { TIMESHEET_RULES, TIMESHEET_STATUS, ENTRY_TYPES } from '@/core/constants/app.constants'; import { TIMESHEET_RULES, TIMESHEET_STATUS, ENTRY_TYPES } from '@/core/constants/app.constants';
import type { Timesheet, TimesheetEntry, EntryType } from '../timesheet.types'; import type { Timesheet, TimesheetEntry, EntryType } from '../timesheet.types';
import './TimesheetWeekView.scss'; import './TimesheetWeekView.scss';
@@ -126,7 +127,7 @@ export default function TimesheetWeekView() {
useEffect(() => { useEffect(() => {
projectService.getMy() projectService.getMy()
.then(({ data }) => setProjects((data as { items?: unknown[] }).items as { id: number; name: string }[] ?? data as { id: number; name: string }[])) .then(({ data }) => setProjects(toArray<{ id: number; name: string }>(data)))
.catch(() => setProjects([])); .catch(() => setProjects([]));
}, []); }, []);

파일 보기

@@ -7,6 +7,7 @@ import BasePageHeader from '@/core/components/BasePageHeader';
import UserFormDialog from '../components/UserFormDialog'; import UserFormDialog from '../components/UserFormDialog';
import { userService } from '../user.service'; import { userService } from '../user.service';
import type { User } from '../user.types'; import type { User } from '../user.types';
import { toArray } from '@/core/api/utils';
const ROLE_SEVERITY: Record<string, string> = { const ROLE_SEVERITY: Record<string, string> = {
SA: 'danger', PM: 'warning', PCM: 'info', DL: 'success', PTK: 'secondary', USER: 'contrast', SA: 'danger', PM: 'warning', PCM: 'info', DL: 'success', PTK: 'secondary', USER: 'contrast',
@@ -21,7 +22,7 @@ export default function UserListView() {
function load() { function load() {
setLoading(true); setLoading(true);
userService.getAll() userService.getAll()
.then(({ data }) => setUsers((data as { items?: User[] }).items ?? data as User[])) .then(({ data }) => setUsers(toArray<User>(data)))
.catch(() => setUsers([])) .catch(() => setUsers([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }

파일 보기

@@ -11,6 +11,7 @@ import WbsUploadDialog from '../components/WbsUploadDialog';
import { wbsService } from '../wbs.service'; import { wbsService } from '../wbs.service';
import { projectService } from '@/modules/project/project.service'; import { projectService } from '@/modules/project/project.service';
import type { WbsVersion, WbsNode } from '../wbs.types'; import type { WbsVersion, WbsNode } from '../wbs.types';
import { toArray } from '@/core/api/utils';
function nodesToTreeNodes(nodes: WbsNode[]): TreeNode[] { function nodesToTreeNodes(nodes: WbsNode[]): TreeNode[] {
return nodes.map((n) => ({ return nodes.map((n) => ({
@@ -31,14 +32,14 @@ export default function WbsTreeView() {
useEffect(() => { useEffect(() => {
projectService.getAll() projectService.getAll()
.then(({ data }) => setProjects((data as { items?: unknown[] }).items as { id: number; name: string; code: string }[] ?? data as { id: number; name: string; code: string }[])) .then(({ data }) => setProjects(toArray<{ id: number; name: string; code: string }>(data)))
.catch(() => setProjects([])); .catch(() => setProjects([]));
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!selectedProjectId) { setVersions([]); return; } if (!selectedProjectId) { setVersions([]); return; }
wbsService.getVersions(selectedProjectId) wbsService.getVersions(selectedProjectId)
.then(({ data }) => setVersions(data as WbsVersion[])) .then(({ data }) => setVersions(toArray<WbsVersion>(data)))
.catch(() => setVersions([])); .catch(() => setVersions([]));
}, [selectedProjectId]); }, [selectedProjectId]);
@@ -46,7 +47,7 @@ export default function WbsTreeView() {
if (!selectedProjectId || !selectedVersion) { setTreeNodes([]); return; } if (!selectedProjectId || !selectedVersion) { setTreeNodes([]); return; }
setLoading(true); setLoading(true);
wbsService.getVersionNodes(selectedProjectId, selectedVersion) wbsService.getVersionNodes(selectedProjectId, selectedVersion)
.then(({ data }) => setTreeNodes(nodesToTreeNodes(data as WbsNode[]))) .then(({ data }) => setTreeNodes(nodesToTreeNodes(toArray<WbsNode>(data))))
.catch(() => setTreeNodes([])) .catch(() => setTreeNodes([]))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}, [selectedProjectId, selectedVersion]); }, [selectedProjectId, selectedVersion]);
@@ -56,7 +57,7 @@ export default function WbsTreeView() {
await wbsService.upload(selectedProjectId, file, effectiveDate); await wbsService.upload(selectedProjectId, file, effectiveDate);
setUploadVisible(false); setUploadVisible(false);
const { data } = await wbsService.getVersions(selectedProjectId); const { data } = await wbsService.getVersions(selectedProjectId);
setVersions(data as WbsVersion[]); setVersions(toArray<WbsVersion>(data));
} }
return ( return (

파일 보기

@@ -37,8 +37,8 @@ function filterByRole(items: typeof MENU_ITEMS, roles: string[]) {
})); }));
} }
const sidebarWidth = computed(() => const sidebarStyle = computed(() =>
props.collapsed ? `${LAYOUT.sidebarCollapsedWidth}px` : `${LAYOUT.sidebarWidth}px`, props.mobile ? {} : { width: props.collapsed ? `${LAYOUT.sidebarCollapsedWidth}px` : `${LAYOUT.sidebarWidth}px` },
); );
</script> </script>
@@ -50,7 +50,7 @@ const sidebarWidth = computed(() =>
'app-sidebar--collapsed': collapsed, 'app-sidebar--collapsed': collapsed,
'app-sidebar--mobile': mobile, 'app-sidebar--mobile': mobile,
}" }"
:style="{ width: sidebarWidth }" :style="sidebarStyle"
> >
<!-- Logo --> <!-- Logo -->
<div class="app-sidebar__header"> <div class="app-sidebar__header">