ActivityPanel entity düzenlemesi yapıldı

This commit is contained in:
Sedat ÖZTÜRK 2025-10-13 16:25:28 +03:00
parent d77675108e
commit f4106ab714
5 changed files with 88 additions and 86 deletions

View file

@ -20,10 +20,10 @@ export interface ActivityItem {
content: string
creatorId?: string
creationTime?: Date
attachedFiles?: FileData[]
attachedFiles?: ActivityFile[]
}
export interface FileData {
export interface ActivityFile {
id?: string
entityName: string
entityId: string

View file

@ -13,17 +13,15 @@ import { Activity } from '@/proxy/formActivity/models'
interface ActivityListProps {
activities: Activity[]
onDeleteNote?: (noteId: string) => void
onDeleteActivity?: (activityId: string) => void
onDeleteFile?: (fileId: string) => void
onDeleteMessage?: (messageId: string) => void
onDownloadFile?: (fileData: any) => void
}
export const ActivityList: React.FC<ActivityListProps> = ({
activities,
onDeleteNote,
onDeleteActivity,
onDeleteFile,
onDeleteMessage,
onDownloadFile,
}) => {
const formatDate = (date: Date) => {
@ -48,14 +46,7 @@ export const ActivityList: React.FC<ActivityListProps> = ({
}
const handleDelete = (activity: Activity) => {
switch (activity.type) {
case 'note':
onDeleteNote?.(activity.id)
break
case 'message':
onDeleteMessage?.(activity.id)
break
}
onDeleteActivity?.(activity.id)
}
const handleDownloadFile = (fileData: any) => {

View file

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'
import { Button, Input, Dialog, Select } from '@/components/ui'
import { FaFileUpload, FaEnvelope, FaStickyNote, FaUsers, FaTimes, FaPlus, FaTrash, FaPaperclip } from 'react-icons/fa'
import { FileData } from '@/proxy/formActivity/models'
import { ActivityFile } from '@/proxy/formActivity/models'
import { getUsers } from '@/services/identity.service'
import { IdentityUserDto } from '@/proxy/admin/models'
@ -234,7 +234,7 @@ export const AddNoteModal: React.FC<AddNoteModalProps> = ({ isOpen, onClose, onS
interface AddFileModalProps {
isOpen: boolean
onClose: () => void
onUpload: (file: File) => Promise<FileData>
onUpload: (file: File) => Promise<ActivityFile>
}
export const AddFileModal: React.FC<AddFileModalProps> = ({ isOpen, onClose, onUpload }) => {

View file

@ -9,7 +9,6 @@ import {
FaPlus,
FaEnvelope,
FaTimes,
FaHistory,
FaGripVertical,
} from 'react-icons/fa'
@ -37,14 +36,11 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
const buttonRef = useRef<HTMLDivElement>(null)
const {
notes,
messages,
activities,
addContent,
sendMessage,
deleteNote,
deleteActivity,
deleteFile,
deleteMessage,
addNote,
sendMessage,
} = useFormActivity(entityName, entityId)
const handleDownloadFile = (fileData: any) => {
@ -55,7 +51,9 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
link.click()
}
const getTotalCount = () => notes.length + messages.length
const getTotalCount = () => activities.length
const getNoteCount = () => activities.filter(a => a.type === 'note').length
const getMessageCount = () => activities.filter(a => a.type === 'message').length
// Mouse drag handlers
const handleMouseDown = (e: React.MouseEvent) => {
@ -181,19 +179,27 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
>
<div className="flex items-center gap-2">
{isVisible ? <FaChevronRight /> : <FaChevronLeft />}
<FaHistory />
{getTotalCount() > 0 && <Badge content={getTotalCount()} />}
</div>
</Button>
</div>
</div>
{/* Overlay - Click outside to close */}
{isVisible && (
<div
className="fixed inset-0 bg-black bg-opacity-25 z-20"
onClick={onToggle}
/>
)}
{/* Activity Panel */}
<div
className={`fixed right-0 top-0 h-full bg-white border-l border-gray-300 shadow-xl transform transition-transform duration-300 ease-in-out z-30 ${
isVisible ? 'translate-x-0' : 'translate-x-full'
}`}
style={{ width: '400px' }}
onClick={(e) => e.stopPropagation()}
>
<div className="flex flex-col h-full">
{/* Header */}
@ -254,7 +260,7 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
: 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
Notlar ({notes.length})
Notlar ({getNoteCount()})
</button>
<button
@ -265,7 +271,7 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
: 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
Mesajlar ({messages.length})
Mesajlar ({getMessageCount()})
</button>
</div>
</div>
@ -275,9 +281,8 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
{activeTab === 'activities' && (
<ActivityList
activities={activities}
onDeleteNote={deleteNote}
onDeleteActivity={deleteActivity}
onDeleteFile={deleteFile}
onDeleteMessage={deleteMessage}
onDownloadFile={handleDownloadFile}
/>
)}
@ -285,9 +290,8 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
{activeTab === 'notes' && (
<ActivityList
activities={activities.filter((a) => a.type === 'note')}
onDeleteNote={deleteNote}
onDeleteActivity={deleteActivity}
onDeleteFile={deleteFile}
onDeleteMessage={deleteMessage}
onDownloadFile={handleDownloadFile}
/>
)}
@ -295,9 +299,8 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
{activeTab === 'messages' && (
<ActivityList
activities={activities.filter((a) => a.type === 'message')}
onDeleteNote={deleteNote}
onDeleteActivity={deleteActivity}
onDeleteFile={deleteFile}
onDeleteMessage={deleteMessage}
onDownloadFile={handleDownloadFile}
/>
)}
@ -309,7 +312,7 @@ export const FormActivityPanel: React.FC<ActivityPanelProps> = ({
<AddContentModal
isOpen={showAddContent}
onClose={() => setShowAddContent(false)}
onSaveContent={addContent}
onSaveContent={addNote}
/>
<SendMessageModal

View file

@ -1,12 +1,14 @@
import { ActivityItem, FileData, Activity } from '@/proxy/formActivity/models'
import { ActivityItem, ActivityFile, Activity } from '@/proxy/formActivity/models'
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<ActivityItem[]>([])
const [files, setFiles] = useState<FileData[]>([])
const [files, setFiles] = useState<ActivityFile[]>([])
const [activities, setActivities] = useState<Activity[]>([])
const { user } = useStoreState((state) => state.auth)
const storageKey = `${STORAGE_PREFIX}${entityName}_${entityId}`
@ -23,7 +25,7 @@ export const useFormActivity = (entityName: string, entityId: string) => {
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 }))
...oldMessages.map((message: any) => ({ ...message, type: 'message' as const })),
]
setActivityItems(parsed.activityItems || combinedActivityItems || [])
setFiles(parsed.files || [])
@ -38,7 +40,7 @@ export const useFormActivity = (entityName: string, entityId: string) => {
const allActivities: Activity[] = []
// Convert all activity items to activities
activityItems.forEach(item => {
activityItems.forEach((item) => {
allActivities.push({
id: item.id || `${item.type}_${Date.now()}`,
type: item.type,
@ -47,12 +49,14 @@ export const useFormActivity = (entityName: string, entityId: string) => {
recipientUserName: item.recipientUserName,
creationTime: item.creationTime || new Date(),
creatorId: item.creatorId || 'Bilinmeyen',
data: item
data: item,
})
})
// Sort by timestamp (newest first)
allActivities.sort((a, b) => new Date(b.creationTime).getTime() - new Date(a.creationTime).getTime())
allActivities.sort(
(a, b) => new Date(b.creationTime).getTime() - new Date(a.creationTime).getTime(),
)
setActivities(allActivities)
}, [activityItems, files])
@ -62,27 +66,27 @@ export const useFormActivity = (entityName: string, entityId: string) => {
const dataToSave = {
activityItems,
files
files,
}
localStorage.setItem(storageKey, JSON.stringify(dataToSave))
}, [activityItems, files, storageKey])
const addNote = (subject: string, content: string) => {
const addActivity = (subject: string, content: string, type: 'note' | 'message' = 'note') => {
const newActivityItem: ActivityItem = {
id: `note_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
type: 'note',
id: `${type}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
type,
entityName,
entityId,
subject,
content,
creatorId: 'Mevcut Kullanıcı', // Bu gerçek implementasyonda authentication'dan gelecek
creationTime: new Date()
creatorId: user.id,
creationTime: new Date(),
}
setActivityItems(prev => [...prev, newActivityItem])
setActivityItems((prev) => [...prev, newActivityItem])
return newActivityItem
}
const addContent = async (subject: string, content: string, files: File[]) => {
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)}`
@ -94,19 +98,19 @@ export const useFormActivity = (entityName: string, entityId: string) => {
entityId,
subject,
content: content || (files.length > 0 ? `${files.length} dosya eklendi` : ''),
creatorId: 'Mevcut Kullanıcı',
creatorId: user.id,
creationTime: timestamp,
attachedFiles: [] // Dosyaları buraya ekleyeceğiz
attachedFiles: [], // Dosyaları buraya ekleyeceğiz
}
// Dosyaları yükle ve note'a attach et
const uploadedFiles: FileData[] = []
const uploadedFiles: ActivityFile[] = []
for (const file of files) {
try {
const uploadedFile = await new Promise<FileData>((resolve, reject) => {
const uploadedFile = await new Promise<ActivityFile>((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => {
const newFile: FileData = {
const newFile: ActivityFile = {
id: `${baseId}_file_${Math.random().toString(36).substr(2, 9)}`,
entityName,
entityId,
@ -114,8 +118,8 @@ export const useFormActivity = (entityName: string, entityId: string) => {
fileSize: file.size,
fileType: file.type,
filePath: `uploads/${entityName}/${entityId}/${file.name}`,
creatorId: 'Mevcut Kullanıcı',
creationTime: timestamp
creatorId: user.id,
creationTime: timestamp,
}
resolve(newFile)
}
@ -132,22 +136,22 @@ export const useFormActivity = (entityName: string, entityId: string) => {
newActivityItem.attachedFiles = uploadedFiles
// Activity Item'ı kaydet
setActivityItems(prev => [...prev, newActivityItem])
setActivityItems((prev) => [...prev, newActivityItem])
// Dosyaları ayrı ayrı da kaydet (eski sistem uyumluluğu için)
if (uploadedFiles.length > 0) {
setFiles(prev => [...prev, ...uploadedFiles])
setFiles((prev) => [...prev, ...uploadedFiles])
}
return newActivityItem
}
const addFile = (file: File) => {
return new Promise<FileData>((resolve, reject) => {
return new Promise<ActivityFile>((resolve, reject) => {
// Simulate file upload - gerçek implementasyonda API call yapılacak
const reader = new FileReader()
reader.onload = () => {
const newFile: FileData = {
const newFile: ActivityFile = {
id: `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
entityName,
entityId,
@ -155,10 +159,10 @@ export const useFormActivity = (entityName: string, entityId: string) => {
fileSize: file.size,
fileType: file.type,
filePath: `uploads/${entityName}/${entityId}/${file.name}`, // Simulated path
creatorId: 'Mevcut Kullanıcı',
creationTime: new Date()
creatorId: user.id,
creationTime: new Date(),
}
setFiles(prev => [...prev, newFile])
setFiles((prev) => [...prev, newFile])
resolve(newFile)
}
reader.onerror = () => reject(reader.error)
@ -166,8 +170,23 @@ export const useFormActivity = (entityName: string, entityId: string) => {
})
}
const sendMessage = (recipients: Array<{ value: string, label: string, email?: string }>, subject: string, content: string) => {
const newMessageItems: ActivityItem[] = recipients.map(recipient => ({
const deleteActivity = (itemId: string) => {
setActivityItems((prev) => prev.filter((item) => item.id !== itemId))
}
const deleteFile = (fileId: string) => {
setFiles((prev) => prev.filter((file) => file.id !== fileId))
}
const sendMessage = (
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,
@ -176,37 +195,26 @@ export const useFormActivity = (entityName: string, entityId: string) => {
recipientUserName: recipient.label,
subject,
content,
creatorId: 'Mevcut Kullanıcı',
creationTime: new Date()
creatorId: user.id,
creationTime: new Date(),
}))
setActivityItems(prev => [...prev, ...newMessageItems])
// Tüm mesajları activityItems'a ekle
setActivityItems((prev) => [...prev, ...newMessageItems])
return newMessageItems
}
const deleteActivityItem = (itemId: string) => {
setActivityItems(prev => prev.filter(item => item.id !== itemId))
}
const deleteFile = (fileId: string) => {
setFiles(prev => prev.filter(file => file.id !== fileId))
}
// Geriye dönük uyumluluk için
const notes = activityItems.filter(item => item.type === 'note')
const messages = activityItems.filter(item => item.type === 'message')
return {
activityItems,
notes,
files,
messages,
activities,
// Ana aktivite fonksiyonları
addActivity,
deleteActivity,
addNote,
addFile,
addContent,
sendMessage,
deleteNote: deleteActivityItem, // Not silme için
// Dosya işlemleri
addFile,
deleteFile,
deleteMessage: deleteActivityItem // Mesaj silme için
}
}
}