Forum değişiklikleri

This commit is contained in:
Sedat ÖZTÜRK 2025-06-24 10:09:33 +03:00
parent b0311425ce
commit 4252cbf0f5
9 changed files with 212 additions and 140 deletions

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Authorization; using Volo.Abp.Authorization;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
@ -159,7 +158,8 @@ public class ForumAppService : PlatformAppService, IForumAppService
input.Slug, input.Slug,
input.Description, input.Description,
input.Icon, input.Icon,
input.DisplayOrder input.DisplayOrder,
input.TenantId
) )
{ {
IsActive = input.IsActive, IsActive = input.IsActive,
@ -192,6 +192,7 @@ public class ForumAppService : PlatformAppService, IForumAppService
{ {
var category = await _categoryRepository.GetAsync(id); var category = await _categoryRepository.GetAsync(id);
category.IsLocked = !category.IsLocked; category.IsLocked = !category.IsLocked;
await _categoryRepository.UpdateAsync(category); await _categoryRepository.UpdateAsync(category);
return ObjectMapper.Map<ForumCategory, ForumCategoryDto>(category); return ObjectMapper.Map<ForumCategory, ForumCategoryDto>(category);
} }
@ -201,6 +202,7 @@ public class ForumAppService : PlatformAppService, IForumAppService
{ {
var category = await _categoryRepository.GetAsync(id); var category = await _categoryRepository.GetAsync(id);
category.IsActive = !category.IsActive; category.IsActive = !category.IsActive;
await _categoryRepository.UpdateAsync(category); await _categoryRepository.UpdateAsync(category);
return ObjectMapper.Map<ForumCategory, ForumCategoryDto>(category); return ObjectMapper.Map<ForumCategory, ForumCategoryDto>(category);
} }
@ -281,7 +283,8 @@ public class ForumAppService : PlatformAppService, IForumAppService
input.Content, input.Content,
input.CategoryId, input.CategoryId,
CurrentUser.Id.Value, CurrentUser.Id.Value,
CurrentUser.Name CurrentUser.Name,
input.TenantId
) )
{ {
IsPinned = input.IsPinned, IsPinned = input.IsPinned,
@ -380,7 +383,8 @@ public class ForumAppService : PlatformAppService, IForumAppService
input.Content, input.Content,
CurrentUser.Id.Value, CurrentUser.Id.Value,
CurrentUser.Name, CurrentUser.Name,
input.ParentPostId input.ParentPostId,
input.TenantId
); );
await _postRepository.InsertAsync(post, autoSave: true); await _postRepository.InsertAsync(post, autoSave: true);
@ -473,24 +477,6 @@ public class ForumAppService : PlatformAppService, IForumAppService
await _categoryRepository.UpdateAsync(category); await _categoryRepository.UpdateAsync(category);
} }
// Like/Unlike topic
public async Task<ForumTopicDto> LikeTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.LikeCount++;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> UnlikeTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.LikeCount = Math.Max(0, topic.LikeCount - 1);
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
// Like/Unlike posts
public async Task<ForumPostDto> LikePostAsync(Guid id) public async Task<ForumPostDto> LikePostAsync(Guid id)
{ {
var post = await _postRepository.GetAsync(id); var post = await _postRepository.GetAsync(id);
@ -523,6 +509,96 @@ public class ForumAppService : PlatformAppService, IForumAppService
return ObjectMapper.Map<ForumPost, ForumPostDto>(post); return ObjectMapper.Map<ForumPost, ForumPostDto>(post);
} }
public async Task<ForumPostDto> MarkPostAsync(Guid id)
{
var post = await _postRepository.GetAsync(id);
post.IsAcceptedAnswer = true;
await _postRepository.UpdateAsync(post);
return ObjectMapper.Map<ForumPost, ForumPostDto>(post);
}
public async Task<ForumPostDto> UnmarkPostAsync(Guid id)
{
var post = await _postRepository.GetAsync(id);
post.IsAcceptedAnswer = false;
await _postRepository.UpdateAsync(post);
return ObjectMapper.Map<ForumPost, ForumPostDto>(post);
}
// Like/Unlike topic
public async Task<ForumTopicDto> LikeTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.LikeCount++;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> UnlikeTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.LikeCount = Math.Max(0, topic.LikeCount - 1);
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> PinTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.IsPinned = true;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> UnpinTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.IsPinned = false;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> LockTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.IsLocked = true;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> UnlockTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.IsLocked = false;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> SolvedTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.IsSolved = true;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
public async Task<ForumTopicDto> UnsolvedTopicAsync(Guid id)
{
var topic = await _topicRepository.GetAsync(id);
topic.IsSolved = false;
await _topicRepository.UpdateAsync(topic);
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
}
// Statistics // Statistics
public async Task<ForumStatsDto> GetForumStatsAsync() public async Task<ForumStatsDto> GetForumStatsAsync()
{ {

View file

@ -5,6 +5,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<UserSecretsId>467bbc0f-83d0-40d0-a9f2-230c8620bdad</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "index.html", "url": "index.html",
"revision": "0.mvu82hb2mqg" "revision": "0.m83v8d1s4bo"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

View file

@ -159,14 +159,6 @@ class ForumService {
}) })
} }
// async toggleCategoryStatus(id: string): Promise<ForumCategory> {
// const response = await apiService.fetchData<ForumCategory>({
// url: `/api/app/forum/categories/${id}/toggle-status`,
// method: 'POST',
// })
// return response.data
// }
// Topics // Topics
async getTopics(params: TopicListParams = {}): Promise<PaginatedResponse<ForumTopic>> { async getTopics(params: TopicListParams = {}): Promise<PaginatedResponse<ForumTopic>> {
const response = await apiService.fetchData<PaginatedResponse<ForumTopic>>({ const response = await apiService.fetchData<PaginatedResponse<ForumTopic>>({
@ -210,9 +202,25 @@ class ForumService {
}) })
} }
async likeTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/${id}/like-topic`,
method: 'POST',
})
return response.data
}
async unlikeTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/${id}/unlike-topic`,
method: 'POST',
})
return response.data
}
async pinTopic(id: string): Promise<ForumTopic> { async pinTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/topics/${id}/pin`, url: `/api/app/forum/${id}/pin-topic`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
@ -220,7 +228,7 @@ class ForumService {
async unpinTopic(id: string): Promise<ForumTopic> { async unpinTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/topics/${id}/unpin`, url: `/api/app/forum/${id}/unpin-topic`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
@ -228,7 +236,7 @@ class ForumService {
async lockTopic(id: string): Promise<ForumTopic> { async lockTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/topics/${id}/lock`, url: `/api/app/forum/${id}/lock-topic`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
@ -236,23 +244,23 @@ class ForumService {
async unlockTopic(id: string): Promise<ForumTopic> { async unlockTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/topics/${id}/unlock`, url: `/api/app/forum/${id}/unlock-topic`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
} }
async markTopicAsSolved(id: string): Promise<ForumTopic> { async solvedTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/topics/${id}/mark-solved`, url: `/api/app/forum/${id}/solved-topic`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
} }
async markTopicAsUnsolved(id: string): Promise<ForumTopic> { async unsolvedTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({ const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/topics/${id}/mark-unsolved`, url: `/api/app/forum/${id}/unsolved-topic`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
@ -287,7 +295,7 @@ class ForumService {
async updatePost(id: string, data: Partial<CreatePostRequest>): Promise<ForumPost> { async updatePost(id: string, data: Partial<CreatePostRequest>): Promise<ForumPost> {
const response = await apiService.fetchData<ForumPost>({ const response = await apiService.fetchData<ForumPost>({
url: `/api/app/forum/posts/${id}`, url: `/api/app/forum/${id}/post`,
method: 'PUT', method: 'PUT',
data, data,
}) })
@ -296,7 +304,7 @@ class ForumService {
async deletePost(id: string): Promise<void> { async deletePost(id: string): Promise<void> {
await apiService.fetchData({ await apiService.fetchData({
url: `/api/app/forum/posts/${id}`, url: `/api/app/forum/${id}/post`,
method: 'DELETE', method: 'DELETE',
}) })
} }
@ -317,25 +325,9 @@ class ForumService {
return response.data return response.data
} }
async likeTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/${id}/like-topic`,
method: 'POST',
})
return response.data
}
async unlikeTopic(id: string): Promise<ForumTopic> {
const response = await apiService.fetchData<ForumTopic>({
url: `/api/app/forum/${id}/unlike-topic`,
method: 'POST',
})
return response.data
}
async markPostAsAcceptedAnswer(id: string): Promise<ForumPost> { async markPostAsAcceptedAnswer(id: string): Promise<ForumPost> {
const response = await apiService.fetchData<ForumPost>({ const response = await apiService.fetchData<ForumPost>({
url: `/api/app/forum/posts/${id}/mark-accepted`, url: `/api/app/forum/${id}/mark-post`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data
@ -343,7 +335,7 @@ class ForumService {
async unmarkPostAsAcceptedAnswer(id: string): Promise<ForumPost> { async unmarkPostAsAcceptedAnswer(id: string): Promise<ForumPost> {
const response = await apiService.fetchData<ForumPost>({ const response = await apiService.fetchData<ForumPost>({
url: `/api/app/forum/posts/${id}/unmark-accepted`, url: `/api/app/forum/${id}/unmark-post`,
method: 'POST', method: 'POST',
}) })
return response.data return response.data

View file

@ -24,8 +24,8 @@ export function Management() {
unpinTopic, unpinTopic,
lockTopic, lockTopic,
unlockTopic, unlockTopic,
markTopicAsSolved, solvedTopic,
markTopicAsUnsolved, unsolvedTopic,
createPost, createPost,
updatePost, updatePost,
deletePost, deletePost,
@ -91,8 +91,8 @@ export function Management() {
onUnpinTopic={(id) => unpinTopic(id).then(() => {})} onUnpinTopic={(id) => unpinTopic(id).then(() => {})}
onLockTopic={(id) => lockTopic(id).then(() => {})} onLockTopic={(id) => lockTopic(id).then(() => {})}
onUnlockTopic={(id) => unlockTopic(id).then(() => {})} onUnlockTopic={(id) => unlockTopic(id).then(() => {})}
onMarkTopicAsSolved={(id) => markTopicAsSolved(id).then(() => {})} onMarkTopicAsSolved={(id) => solvedTopic(id).then(() => {})}
onMarkTopicAsUnsolved={(id) => markTopicAsUnsolved(id).then(() => {})} onMarkTopicAsUnsolved={(id) => unsolvedTopic(id).then(() => {})}
onCreatePost={(data) => createPost(data).then(() => {})} onCreatePost={(data) => createPost(data).then(() => {})}
onUpdatePost={(id, data) => updatePost(id, data).then(() => {})} onUpdatePost={(id, data) => updatePost(id, data).then(() => {})}
onDeletePost={(id) => deletePost(id).then(() => {})} onDeletePost={(id) => deletePost(id).then(() => {})}

View file

@ -1,56 +1,52 @@
import React, { useState } from 'react'; import React, { useState } from 'react'
import { Folder, MessageSquare, FileText, Plus, BarChart3 } from 'lucide-react'; import { Folder, MessageSquare, FileText, Plus, BarChart3 } from 'lucide-react'
import { CategoryManagement } from './CategoryManagement'; import { CategoryManagement } from './CategoryManagement'
import { TopicManagement } from './TopicManagement'; import { TopicManagement } from './TopicManagement'
import { PostManagement } from './PostManagement'; import { PostManagement } from './PostManagement'
import { AdminStats } from './AdminStats'; import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'; import { AdminStats } from './Dashboard'
interface AdminViewProps { interface AdminViewProps {
categories: ForumCategory[]; categories: ForumCategory[]
topics: ForumTopic[]; topics: ForumTopic[]
posts: ForumPost[]; posts: ForumPost[]
loading: boolean; loading: boolean
onCreateCategory: (category: { onCreateCategory: (category: {
name: string; name: string
slug: string; slug: string
description: string; description: string
icon: string; icon: string
displayOrder: number; displayOrder: number
isActive: boolean; isActive: boolean
isLocked: boolean; isLocked: boolean
}) => Promise<void>; }) => Promise<void>
onUpdateCategory: (id: string, category: Partial<ForumCategory>) => Promise<void>; onUpdateCategory: (id: string, category: Partial<ForumCategory>) => Promise<void>
onUpdateCategoryLockState: (id: string) => Promise<void>; onUpdateCategoryLockState: (id: string) => Promise<void>
onUpdateCategoryActiveState: (id: string) => Promise<void>; onUpdateCategoryActiveState: (id: string) => Promise<void>
onDeleteCategory: (id: string) => Promise<void>; onDeleteCategory: (id: string) => Promise<void>
onCreateTopic: (topic: { onCreateTopic: (topic: {
title: string; title: string
content: string; content: string
categoryId: string; categoryId: string
isPinned?: boolean; isPinned?: boolean
isLocked?: boolean; isLocked?: boolean
}) => Promise<void>; }) => Promise<void>
onUpdateTopic: (id: string, topic: Partial<ForumTopic>) => Promise<void>; onUpdateTopic: (id: string, topic: Partial<ForumTopic>) => Promise<void>
onDeleteTopic: (id: string) => Promise<void>; onDeleteTopic: (id: string) => Promise<void>
onPinTopic: (id: string) => Promise<void>; onPinTopic: (id: string) => Promise<void>
onUnpinTopic: (id: string) => Promise<void>; onUnpinTopic: (id: string) => Promise<void>
onLockTopic: (id: string) => Promise<void>; onLockTopic: (id: string) => Promise<void>
onUnlockTopic: (id: string) => Promise<void>; onUnlockTopic: (id: string) => Promise<void>
onMarkTopicAsSolved: (id: string) => Promise<void>; onMarkTopicAsSolved: (id: string) => Promise<void>
onMarkTopicAsUnsolved: (id: string) => Promise<void>; onMarkTopicAsUnsolved: (id: string) => Promise<void>
onCreatePost: (post: { onCreatePost: (post: { topicId: string; content: string; parentPostId?: string }) => Promise<void>
topicId: string; onUpdatePost: (id: string, post: Partial<ForumPost>) => Promise<void>
content: string; onDeletePost: (id: string) => Promise<void>
parentPostId?: string; onMarkPostAsAcceptedAnswer: (id: string) => Promise<void>
}) => Promise<void>; onUnmarkPostAsAcceptedAnswer: (id: string) => Promise<void>
onUpdatePost: (id: string, post: Partial<ForumPost>) => Promise<void>;
onDeletePost: (id: string) => Promise<void>;
onMarkPostAsAcceptedAnswer: (id: string) => Promise<void>;
onUnmarkPostAsAcceptedAnswer: (id: string) => Promise<void>;
} }
type AdminSection = 'stats' | 'categories' | 'topics' | 'posts'; type AdminSection = 'stats' | 'categories' | 'topics' | 'posts'
export function AdminView({ export function AdminView({
categories, categories,
@ -75,16 +71,16 @@ export function AdminView({
onUpdatePost, onUpdatePost,
onDeletePost, onDeletePost,
onMarkPostAsAcceptedAnswer, onMarkPostAsAcceptedAnswer,
onUnmarkPostAsAcceptedAnswer onUnmarkPostAsAcceptedAnswer,
}: AdminViewProps) { }: AdminViewProps) {
const [activeSection, setActiveSection] = useState<AdminSection>('stats'); const [activeSection, setActiveSection] = useState<AdminSection>('stats')
const navigationItems = [ const navigationItems = [
{ id: 'stats' as AdminSection, label: 'Dashboard', icon: BarChart3 }, { id: 'stats' as AdminSection, label: 'Dashboard', icon: BarChart3 },
{ id: 'categories' as AdminSection, label: 'Categories', icon: Folder }, { id: 'categories' as AdminSection, label: 'Categories', icon: Folder },
{ id: 'topics' as AdminSection, label: 'Topics', icon: MessageSquare }, { id: 'topics' as AdminSection, label: 'Topics', icon: MessageSquare },
{ id: 'posts' as AdminSection, label: 'Posts', icon: FileText }, { id: 'posts' as AdminSection, label: 'Posts', icon: FileText },
]; ]
return ( return (
<div className="mx-auto px-4 sm:px-6 lg:px-8 py-8"> <div className="mx-auto px-4 sm:px-6 lg:px-8 py-8">
@ -93,7 +89,7 @@ export function AdminView({
<div className="lg:w-64 flex-shrink-0"> <div className="lg:w-64 flex-shrink-0">
<nav className="space-y-2"> <nav className="space-y-2">
{navigationItems.map((item) => { {navigationItems.map((item) => {
const Icon = item.icon; const Icon = item.icon
return ( return (
<button <button
key={item.id} key={item.id}
@ -107,7 +103,7 @@ export function AdminView({
<Icon className="w-5 h-5" /> <Icon className="w-5 h-5" />
<span className="font-medium">{item.label}</span> <span className="font-medium">{item.label}</span>
</button> </button>
); )
})} })}
</nav> </nav>
</div> </div>
@ -162,5 +158,5 @@ export function AdminView({
</div> </div>
</div> </div>
</div> </div>
); )
} }

View file

@ -1,6 +1,8 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Plus, Edit2, Trash2, CheckCircle, Circle, Heart, Loader2 } from 'lucide-react' import { Plus, Edit2, Trash2, CheckCircle, Circle, Heart, Loader2 } from 'lucide-react'
import { ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumPost, ForumTopic } from '@/proxy/forum/forum'
import ReactQuill from 'react-quill'
import 'react-quill/dist/quill.snow.css'
interface PostManagementProps { interface PostManagementProps {
posts: ForumPost[] posts: ForumPost[]
@ -23,11 +25,11 @@ export function PostManagement({
onMarkPostAsAcceptedAnswer, onMarkPostAsAcceptedAnswer,
onUnmarkPostAsAcceptedAnswer, onUnmarkPostAsAcceptedAnswer,
}: PostManagementProps) { }: PostManagementProps) {
const [content, setContent] = useState('')
const [showCreateForm, setShowCreateForm] = useState(false) const [showCreateForm, setShowCreateForm] = useState(false)
const [editingPost, setEditingPost] = useState<ForumPost | null>(null) const [editingPost, setEditingPost] = useState<ForumPost | null>(null)
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
topicId: '', topicId: '',
content: '',
isAcceptedAnswer: false, isAcceptedAnswer: false,
}) })
const [submitting, setSubmitting] = useState(false) const [submitting, setSubmitting] = useState(false)
@ -35,7 +37,6 @@ export function PostManagement({
const resetForm = () => { const resetForm = () => {
setFormData({ setFormData({
topicId: '', topicId: '',
content: '',
isAcceptedAnswer: false, isAcceptedAnswer: false,
}) })
setShowCreateForm(false) setShowCreateForm(false)
@ -44,15 +45,18 @@ export function PostManagement({
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
if (submitting) return if (submitting || !content.trim()) return
try { try {
setSubmitting(true) setSubmitting(true)
const data = { ...formData, content: content.trim() }
if (editingPost) { if (editingPost) {
await onUpdatePost(editingPost.id, formData) await onUpdatePost(editingPost.id, data)
} else { } else {
await onCreatePost(formData) await onCreatePost(data)
} }
resetForm() resetForm()
} catch (error) { } catch (error) {
console.error('Error submitting form:', error) console.error('Error submitting form:', error)
@ -65,9 +69,9 @@ export function PostManagement({
setEditingPost(post) setEditingPost(post)
setFormData({ setFormData({
topicId: post.topicId, topicId: post.topicId,
content: post.content,
isAcceptedAnswer: post.isAcceptedAnswer, isAcceptedAnswer: post.isAcceptedAnswer,
}) })
setContent(post.content)
setShowCreateForm(true) setShowCreateForm(true)
} }
@ -151,12 +155,12 @@ export function PostManagement({
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1">Content</label> <label className="block text-sm font-medium text-gray-700 mb-1">Content</label>
<textarea <ReactQuill
value={formData.content} theme="snow"
onChange={(e) => setFormData({ ...formData, content: e.target.value })} value={content}
rows={6} onChange={setContent}
className="w-full border border-gray-300 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-transparent" style={{ height: '400px', marginBottom: '50px' }}
required placeholder={'Write your message...'}
/> />
</div> </div>
@ -230,7 +234,10 @@ export function PostManagement({
Reply to:{' '} Reply to:{' '}
<span className="font-medium">{getTopicTitle(post.topicId)}</span> <span className="font-medium">{getTopicTitle(post.topicId)}</span>
</p> </p>
<p className="text-gray-700 line-clamp-3">{post.content}</p> <p
className="text-gray-700 line-clamp-3"
dangerouslySetInnerHTML={{ __html: post.content }}
></p>
</div> </div>
<div className="flex items-center justify-between text-sm text-gray-500"> <div className="flex items-center justify-between text-sm text-gray-500">

View file

@ -248,9 +248,9 @@ export function useForumData() {
} }
} }
const markTopicAsSolved = async (id: string) => { const solvedTopic = async (id: string) => {
try { try {
const updatedTopic = await forumService.markTopicAsSolved(id) const updatedTopic = await forumService.solvedTopic(id)
setTopics((prev) => prev.map((topic) => (topic.id === id ? updatedTopic : topic))) setTopics((prev) => prev.map((topic) => (topic.id === id ? updatedTopic : topic)))
return updatedTopic return updatedTopic
} catch (err) { } catch (err) {
@ -260,9 +260,9 @@ export function useForumData() {
} }
} }
const markTopicAsUnsolved = async (id: string) => { const unsolvedTopic = async (id: string) => {
try { try {
const updatedTopic = await forumService.markTopicAsUnsolved(id) const updatedTopic = await forumService.unsolvedTopic(id)
setTopics((prev) => prev.map((topic) => (topic.id === id ? updatedTopic : topic))) setTopics((prev) => prev.map((topic) => (topic.id === id ? updatedTopic : topic)))
return updatedTopic return updatedTopic
} catch (err) { } catch (err) {
@ -432,8 +432,8 @@ export function useForumData() {
unpinTopic, unpinTopic,
lockTopic, lockTopic,
unlockTopic, unlockTopic,
markTopicAsSolved, solvedTopic,
markTopicAsUnsolved, unsolvedTopic,
// Post operations // Post operations
createPost, createPost,