From 5e4726c9bea57a3b01459f6c1df25f938715d991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Mon, 13 Oct 2025 17:58:08 +0300 Subject: [PATCH] =?UTF-8?q?LocalStorage=20kald=C4=B1r=C4=B1ld=C4=B1=20ama?= =?UTF-8?q?=20hen=C3=BCz=20End=20pointler=20ile=20do=C4=9Fru=20=C3=A7al?= =?UTF-8?q?=C4=B1=C5=9Fm=C4=B1yor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FormActivityPanel/FormActivityPanel.tsx | 56 +-- .../form/FormActivityPanel/useFormActivity.ts | 387 +++++++++++------- 2 files changed, 275 insertions(+), 168 deletions(-) diff --git a/ui/src/views/form/FormActivityPanel/FormActivityPanel.tsx b/ui/src/views/form/FormActivityPanel/FormActivityPanel.tsx index 66881926..773b40f6 100644 --- a/ui/src/views/form/FormActivityPanel/FormActivityPanel.tsx +++ b/ui/src/views/form/FormActivityPanel/FormActivityPanel.tsx @@ -37,6 +37,7 @@ export const FormActivityPanel: React.FC = ({ const { activities, + loading, deleteActivity, deleteFile, addNote, @@ -279,31 +280,40 @@ export const FormActivityPanel: React.FC = ({ {/* Content */}
- {activeTab === 'activities' && ( - - )} + {loading ? ( +
+
+ Yükleniyor... +
+ ) : ( + <> + {activeTab === 'activities' && ( + + )} - {activeTab === 'notes' && ( - a.type === 'note')} - onDeleteActivity={deleteActivity} - onDeleteFile={deleteFile} - onDownloadFile={handleDownloadFile} - /> - )} + {activeTab === 'notes' && ( + a.type === 'note')} + onDeleteActivity={deleteActivity} + onDeleteFile={deleteFile} + onDownloadFile={handleDownloadFile} + /> + )} - {activeTab === 'messages' && ( - a.type === 'message')} - onDeleteActivity={deleteActivity} - onDeleteFile={deleteFile} - onDownloadFile={handleDownloadFile} - /> + {activeTab === 'messages' && ( + a.type === 'message')} + onDeleteActivity={deleteActivity} + onDeleteFile={deleteFile} + onDownloadFile={handleDownloadFile} + /> + )} + )}
diff --git a/ui/src/views/form/FormActivityPanel/useFormActivity.ts b/ui/src/views/form/FormActivityPanel/useFormActivity.ts index 69087be5..8e464587 100644 --- a/ui/src/views/form/FormActivityPanel/useFormActivity.ts +++ b/ui/src/views/form/FormActivityPanel/useFormActivity.ts @@ -1,40 +1,81 @@ import { ActivityItem, ActivityFile, Activity } from '@/proxy/formActivity/models' +import { ActivityDto, ActivityItemDto, ActivityFileDto } from '@/proxy/activity/models' +import { activityService } from '@/services/activity.service' import { useStoreState } from '@/store/store' import { useState, useEffect } from 'react' -const STORAGE_PREFIX = 'form_activity_' - export const useFormActivity = (entityName: string, entityId: string) => { const [activityItems, setActivityItems] = useState([]) const [files, setFiles] = useState([]) const [activities, setActivities] = useState([]) + const [loading, setLoading] = useState(false) const { user } = useStoreState((state) => state.auth) - const storageKey = `${STORAGE_PREFIX}${entityName}_${entityId}` - - // Load data from localStorage on component mount + // Load data from API on component mount useEffect(() => { if (!entityName || !entityId) return - - const savedData = localStorage.getItem(storageKey) - if (savedData) { - try { - const parsed = JSON.parse(savedData) - // Eski veriyi yeni yapıya dönüştür - const oldNotes = parsed.notes || [] - const oldMessages = parsed.messages || [] - const combinedActivityItems: ActivityItem[] = [ - ...oldNotes.map((note: any) => ({ ...note, type: 'note' as const })), - ...oldMessages.map((message: any) => ({ ...message, type: 'message' as const })), - ] - setActivityItems(parsed.activityItems || combinedActivityItems || []) - setFiles(parsed.files || []) - } catch (error) { - console.error('Failed to load activity data:', error) - } - } + loadActivitiesFromAPI() }, [entityName, entityId]) + const loadActivitiesFromAPI = async () => { + try { + setLoading(true) + + // Tüm ActivityItem'ları al + const items = await activityService.getItems() + + // EntityName ve EntityId ile filtrele + const filteredItems = items.filter( + item => item.entityName === entityName && item.entityId === entityId + ) + + // DTO'dan ActivityItem'a dönüştür + const convertedItems: ActivityItem[] = filteredItems.map(dto => ({ + id: dto.id, + type: (dto.type as 'note' | 'message') || 'note', + entityName: dto.entityName || entityName, + entityId: dto.entityId || entityId, + recipientUserId: dto.recipientUserId, + recipientUserName: dto.recipientUserName, + subject: dto.subject || '', + content: dto.content || '', + creatorId: dto.creatorId || user.id, + creationTime: dto.creationTime ? new Date(dto.creationTime) : new Date(), + attachedFiles: [] + })) + + // Her ActivityItem için dosyaları yükle + for (const item of convertedItems) { + if (item.id) { + try { + const itemFiles = await activityService.getFiles(item.id) + const convertedFiles: ActivityFile[] = itemFiles.map(fileDto => ({ + id: fileDto.id, + entityName: fileDto.entityName || entityName, + entityId: fileDto.entityId || entityId, + fileName: fileDto.fileName || '', + fileSize: fileDto.fileSize || 0, + fileType: fileDto.fileType || '', + filePath: fileDto.filePath || '', + creatorId: fileDto.creatorId || user.id, + creationTime: fileDto.creationTime ? new Date(fileDto.creationTime) : new Date(), + })) + item.attachedFiles = convertedFiles + setFiles(prev => [...prev, ...convertedFiles]) + } catch (error) { + console.error('Failed to load files for activity item:', item.id, error) + } + } + } + + setActivityItems(convertedItems) + } catch (error) { + console.error('Failed to load activities from API:', error) + } finally { + setLoading(false) + } + } + // Update activities when data changes useEffect(() => { const allActivities: Activity[] = [] @@ -60,161 +101,217 @@ export const useFormActivity = (entityName: string, entityId: string) => { setActivities(allActivities) }, [activityItems, files]) - // Save to localStorage whenever data changes - useEffect(() => { - if (!entityName || !entityId) return - const dataToSave = { - activityItems, - files, - } - localStorage.setItem(storageKey, JSON.stringify(dataToSave)) - }, [activityItems, files, storageKey]) - const addActivity = (subject: string, content: string, type: 'note' | 'message' = 'note') => { - const newActivityItem: ActivityItem = { - id: `${type}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, - type, - entityName, - entityId, - subject, - content, - creatorId: user.id, - creationTime: new Date(), - } - setActivityItems((prev) => [...prev, newActivityItem]) - return newActivityItem - } + const addNote = async (subject: string, content: string, files: File[]) => { - const timestamp = new Date() - const baseId = `content_${timestamp.getTime()}_${Math.random().toString(36).substr(2, 9)}` + try { + setLoading(true) - // Hem not hem de dosya varsa veya sadece biri varsa tek bir note aktivitesi oluştur - const newActivityItem: ActivityItem = { - id: baseId, - type: 'note', - entityName, - entityId, - subject, - content: content || (files.length > 0 ? `${files.length} dosya eklendi` : ''), - creatorId: user.id, - creationTime: timestamp, - attachedFiles: [], // Dosyaları buraya ekleyeceğiz - } + // Önce Activity oluştur + const activityDto: Partial = { + type: 'note', + subject: subject || 'Not', + content: content || (files.length > 0 ? `${files.length} dosya eklendi` : ''), + } + + const createdActivity = await activityService.create(activityDto as ActivityDto) - // Dosyaları yükle ve note'a attach et - const uploadedFiles: ActivityFile[] = [] - for (const file of files) { - try { - const uploadedFile = await new Promise((resolve, reject) => { - const reader = new FileReader() - reader.onload = () => { - const newFile: ActivityFile = { - id: `${baseId}_file_${Math.random().toString(36).substr(2, 9)}`, - entityName, - entityId, - fileName: file.name, - fileSize: file.size, - fileType: file.type, - filePath: `uploads/${entityName}/${entityId}/${file.name}`, - creatorId: user.id, - creationTime: timestamp, - } - resolve(newFile) + // ActivityItem oluştur + const activityItemDto: Partial = { + activityId: createdActivity.id, + type: 'note', + entityName, + entityId, + subject: subject || 'Not', + content: content || (files.length > 0 ? `${files.length} dosya eklendi` : ''), + } + + const createdActivityItem = await activityService.createItem(activityItemDto as ActivityItemDto) + + // Dosyaları yükle + const uploadedFiles: ActivityFile[] = [] + for (const file of files) { + try { + const activityFileDto: Partial = { + activityItemId: createdActivityItem.id, + entityName, + entityId, + fileName: file.name, + fileSize: file.size, + fileType: file.type, + filePath: `uploads/${entityName}/${entityId}/${file.name}`, } - reader.onerror = () => reject(reader.error) - reader.readAsDataURL(file) - }) - uploadedFiles.push(uploadedFile) - } catch (error) { - console.error('File upload failed:', error) - } - } - // Note'a dosyaları ekle - newActivityItem.attachedFiles = uploadedFiles - - // Activity Item'ı kaydet - setActivityItems((prev) => [...prev, newActivityItem]) - - // Dosyaları ayrı ayrı da kaydet (eski sistem uyumluluğu için) - if (uploadedFiles.length > 0) { - setFiles((prev) => [...prev, ...uploadedFiles]) - } - - return newActivityItem - } - - const addFile = (file: File) => { - return new Promise((resolve, reject) => { - // Simulate file upload - gerçek implementasyonda API call yapılacak - const reader = new FileReader() - reader.onload = () => { - const newFile: ActivityFile = { - id: `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, - entityName, - entityId, - fileName: file.name, - fileSize: file.size, - fileType: file.type, - filePath: `uploads/${entityName}/${entityId}/${file.name}`, // Simulated path - creatorId: user.id, - creationTime: new Date(), + const createdFile = await activityService.uploadFile(activityFileDto as ActivityFileDto) + + const newFile: ActivityFile = { + id: createdFile.id, + entityName: createdFile.entityName || entityName, + entityId: createdFile.entityId || entityId, + fileName: createdFile.fileName || file.name, + fileSize: createdFile.fileSize || file.size, + fileType: createdFile.fileType || file.type, + filePath: createdFile.filePath || '', + creatorId: createdFile.creatorId || user.id, + creationTime: createdFile.creationTime ? new Date(createdFile.creationTime) : new Date(), + } + + uploadedFiles.push(newFile) + } catch (error) { + console.error('File upload failed:', error) } - setFiles((prev) => [...prev, newFile]) - resolve(newFile) } - reader.onerror = () => reject(reader.error) - reader.readAsDataURL(file) - }) + + // Yeni ActivityItem'ı local state'e ekle + const newActivityItem: ActivityItem = { + id: createdActivityItem.id, + type: 'note', + entityName, + entityId, + subject: createdActivityItem.subject || '', + content: createdActivityItem.content || '', + creatorId: createdActivityItem.creatorId || user.id, + creationTime: createdActivityItem.creationTime ? new Date(createdActivityItem.creationTime) : new Date(), + attachedFiles: uploadedFiles + } + + setActivityItems((prev) => [...prev, newActivityItem]) + if (uploadedFiles.length > 0) { + setFiles((prev) => [...prev, ...uploadedFiles]) + } + + return newActivityItem + } catch (error) { + console.error('Failed to create note:', error) + throw error + } finally { + setLoading(false) + } } - const deleteActivity = (itemId: string) => { - setActivityItems((prev) => prev.filter((item) => item.id !== itemId)) + + + const deleteActivity = async (itemId: string) => { + try { + // API'dan ActivityItem'ı sil + await activityService.deleteItem(itemId) + + // Local state'ten kaldır + setActivityItems((prev) => prev.filter((item) => item.id !== itemId)) + + // İlgili dosyaları da kaldır + setFiles((prev) => prev.filter((file) => + !(file as any).activityItemId || (file as any).activityItemId !== itemId + )) + } catch (error) { + console.error('Failed to delete activity:', error) + throw error + } } - const deleteFile = (fileId: string) => { - setFiles((prev) => prev.filter((file) => file.id !== fileId)) + const deleteFile = async (fileId: string) => { + try { + // API'dan ActivityFile'ı sil + await activityService.deleteFile(fileId) + + // Local state'ten kaldır + setFiles((prev) => prev.filter((file) => file.id !== fileId)) + + // ActivityItem'dan da kaldır + setActivityItems((prev) => + prev.map(item => ({ + ...item, + attachedFiles: item.attachedFiles?.filter(file => file.id !== fileId) || [] + })) + ) + } catch (error) { + console.error('Failed to delete file:', error) + throw error + } } - const sendMessage = ( + const sendMessage = async ( recipients: Array<{ value: string; label: string; email?: string }>, subject: string, content: string, ) => { - // Her recipient için ayrı mesaj aktivitesi oluştur - const newMessageItems: ActivityItem[] = recipients.map((recipient) => ({ - id: `message_${Date.now()}_${Math.random().toString(36).substr(2, 9)}_${recipient.value}`, - type: 'message' as const, - entityName, - entityId, - recipientUserId: recipient.value, - recipientUserName: recipient.label, - subject, - content, - creatorId: user.id, - creationTime: new Date(), - })) - - // Tüm mesajları activityItems'a ekle - setActivityItems((prev) => [...prev, ...newMessageItems]) - return newMessageItems + try { + setLoading(true) + const newMessageItems: ActivityItem[] = [] + + // Her recipient için ayrı mesaj aktivitesi oluştur + for (const recipient of recipients) { + try { + // Activity oluştur + const activityDto: Partial = { + type: 'message', + subject, + content, + recipientUserName: recipient.label, + } + + const createdActivity = await activityService.create(activityDto as ActivityDto) + + // ActivityItem oluştur + const activityItemDto: Partial = { + activityId: createdActivity.id, + type: 'message', + entityName, + entityId, + recipientUserId: recipient.value, + recipientUserName: recipient.label, + subject, + content, + } + + const createdActivityItem = await activityService.createItem(activityItemDto as ActivityItemDto) + + const newMessageItem: ActivityItem = { + id: createdActivityItem.id, + type: 'message', + entityName, + entityId, + recipientUserId: createdActivityItem.recipientUserId, + recipientUserName: createdActivityItem.recipientUserName, + subject: createdActivityItem.subject || '', + content: createdActivityItem.content || '', + creatorId: createdActivityItem.creatorId || user.id, + creationTime: createdActivityItem.creationTime ? new Date(createdActivityItem.creationTime) : new Date(), + } + + newMessageItems.push(newMessageItem) + } catch (error) { + console.error('Failed to send message to recipient:', recipient.label, error) + } + } + + // Tüm mesajları activityItems'a ekle + setActivityItems((prev) => [...prev, ...newMessageItems]) + return newMessageItems + } catch (error) { + console.error('Failed to send messages:', error) + throw error + } finally { + setLoading(false) + } } return { activityItems, files, activities, + loading, // Ana aktivite fonksiyonları - addActivity, deleteActivity, addNote, sendMessage, // Dosya işlemleri - addFile, deleteFile, + // Veri yenileme + refreshActivities: loadActivitiesFromAPI, } }