REFACTOR(repo): simplify project structure

- Move services/nextjs to nextjs/
- Move deploy/docker/Dockerfile.prod to Dockerfile
- Add GitHub Actions workflows (ci.yml, build.yml)
- Remove deploy/, services/, scripts/ folders
This commit is contained in:
2026-01-05 02:29:10 +09:00
commit e82ea71c22
205 changed files with 21304 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
"use client";
import { useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import { useAuth } from "@/src/app/providers/auth-provider";
import { useDocumentManagementStore } from "@/features/document-management/model/store";
import { useFolderManagementStore } from "@/features/folder-management/model/store";
import { useDocumentStore } from "@/entities/document/model/store";
import { useFolderStore } from "@/entities/folder/model/store";
import { Spinner } from "@/shared/ui/spinner";
import { Header, CreateInput, FolderView, RootView } from "@/widgets/documents";
import { Button } from "@/shared/ui/button";
import { Plus, Folder } from "lucide-react";
import { DocumentsPageSkeleton } from "@/shared/ui/skeleton";
const DocumentsPage = () => {
const { user } = useAuth();
const searchParams = useSearchParams();
const currentFolderId = searchParams?.get('folder');
// Use management stores for operations
const documentManagement = useDocumentManagementStore();
const folderManagement = useFolderManagementStore();
// Use entity stores for state
const documentStore = useDocumentStore();
const folderStore = useFolderStore();
const documents = documentStore.documents;
const folders = folderStore.folders;
const isLoading = documentStore.isLoading || folderStore.isLoading;
// Destructure specific functions
const { fetchDocuments, createDocument } = documentManagement;
const { fetchFolders, createFolder } = folderManagement;
const [isCreatingFolder, setIsCreatingFolder] = useState(false);
const [newFolderName, setNewFolderName] = useState('');
const [refreshKey, setRefreshKey] = useState(0);
// Fetch initial data
useEffect(() => {
fetchDocuments();
fetchFolders();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const handleCreateFolder = async () => {
if (!newFolderName.trim()) return;
const newFolder = await createFolder(newFolderName, currentFolderId);
if (newFolder) {
setNewFolderName('');
setIsCreatingFolder(false);
// Refresh data to show the new folder
fetchFolders();
if (currentFolderId) {
setRefreshKey(prev => prev + 1);
}
}
};
const handleCreateDocumentFromHeader = async () => {
await createDocument(currentFolderId);
if (currentFolderId) {
setRefreshKey(prev => prev + 1);
}
};
const handleNavigateToFolder = (folderId: string) => {
window.history.pushState({}, '', `/documents?folder=${folderId}`);
window.dispatchEvent(new Event('popstate'));
};
const handleGoBack = () => {
window.history.back();
};
const handleFolderDeleted = () => {
// Refresh folders list
fetchFolders();
fetchDocuments();
// Force refresh if we're in a folder view
if (currentFolderId) {
setRefreshKey(prev => prev + 1);
}
};
// Show loading skeleton while data is being fetched
if (isLoading) {
return (
<div className="h-full flex flex-col bg-white dark:bg-[#1F1F1F]">
<Header
userName={user?.name}
documentsCount={documents.length}
foldersCount={folders.length}
isCreating={false}
onCreateFolder={() => setIsCreatingFolder(true)}
onCreateDocument={handleCreateDocumentFromHeader}
/>
<div className="flex-1 overflow-auto bg-gray-50 dark:bg-[#1F1F1F] p-6">
<DocumentsPageSkeleton />
</div>
</div>
);
}
return (
<div className="h-full flex flex-col bg-white dark:bg-[#1F1F1F]">
{/* Header */}
<Header
userName={user?.name}
documentsCount={documents.length}
foldersCount={folders.length}
isCreating={documentManagement.isCreating}
onCreateFolder={() => setIsCreatingFolder(true)}
onCreateDocument={handleCreateDocumentFromHeader}
/>
{/* Create folder input - shown when creating from header */}
{isCreatingFolder && (
<div className="px-6 py-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-secondary">
<CreateInput
value={newFolderName}
onChange={setNewFolderName}
onSubmit={handleCreateFolder}
onCancel={() => {
setIsCreatingFolder(false);
setNewFolderName('');
}}
/>
</div>
)}
{/* Main content - Desktop layout */}
<div className="hidden lg:block flex-1 overflow-hidden bg-gray-50 dark:bg-[#1F1F1F]">
<div className="flex h-full">
<div className="flex-1 overflow-auto">
<div className="p-6">
{currentFolderId ? (
<FolderView
key={`desktop-${currentFolderId}-${refreshKey}`}
folderId={currentFolderId}
onBack={handleGoBack}
onFolderDeleted={handleFolderDeleted}
variant="desktop"
/>
) : (
<RootView
onCreateFolder={() => setIsCreatingFolder(true)}
onNavigateToFolder={handleNavigateToFolder}
onFolderDeleted={handleFolderDeleted}
variant="desktop"
/>
)}
</div>
</div>
</div>
</div>
{/* Mobile layout */}
<div className="lg:hidden flex-1 overflow-auto">
<div className="px-6 py-8 bg-gray-50 dark:bg-[#1F1F1F]">
<div className="max-w-4xl mx-auto space-y-8">
{/* Create folder input */}
{isCreatingFolder && (
<CreateInput
value={newFolderName}
onChange={setNewFolderName}
onSubmit={handleCreateFolder}
onCancel={() => {
setIsCreatingFolder(false);
setNewFolderName('');
}}
/>
)}
{/* Content */}
{currentFolderId ? (
<FolderView
key={`mobile-${currentFolderId}-${refreshKey}`}
folderId={currentFolderId}
onBack={handleGoBack}
onFolderDeleted={handleFolderDeleted}
variant="mobile"
/>
) : (
<RootView
onCreateFolder={() => setIsCreatingFolder(true)}
onNavigateToFolder={handleNavigateToFolder}
onFolderDeleted={handleFolderDeleted}
variant="mobile"
/>
)}
</div>
</div>
</div>
</div>
);
};
export default DocumentsPage;