01252232
This commit is contained in:
parent
700b3eb2c7
commit
6336806073
|
@ -17,7 +17,7 @@ export class PostRouter {
|
|||
constructor(
|
||||
private readonly trpc: TrpcService,
|
||||
private readonly postService: PostService,
|
||||
) {}
|
||||
) { }
|
||||
router = this.trpc.router({
|
||||
create: this.trpc.protectProcedure
|
||||
.input(PostCreateArgsSchema)
|
||||
|
@ -105,8 +105,10 @@ export class PostRouter {
|
|||
select: PostSelectSchema.optional(),
|
||||
}),
|
||||
) // Assuming StaffMethodSchema.findMany is the Zod schema for finding staffs by keyword
|
||||
.query(async ({ input }) => {
|
||||
return await this.postService.findManyWithPagination(input);
|
||||
.query(async ({ input, ctx }) => {
|
||||
const { staff, req } = ctx;
|
||||
const ip = getClientIp(req);
|
||||
return await this.postService.findManyWithPagination(input, staff, ip);
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import { BaseService } from '../base/base.service';
|
|||
import { DepartmentService } from '../department/department.service';
|
||||
import { setPostRelation, updatePostState } from './utils';
|
||||
import EventBus, { CrudOperation } from '@server/utils/event-bus';
|
||||
import { DefaultArgs } from '@prisma/client/runtime/library';
|
||||
|
||||
@Injectable()
|
||||
export class PostService extends BaseService<Prisma.PostDelegate> {
|
||||
|
@ -96,7 +97,24 @@ export class PostService extends BaseService<Prisma.PostDelegate> {
|
|||
return { ...result, items };
|
||||
});
|
||||
}
|
||||
|
||||
async findManyWithPagination(
|
||||
args: { page?: number; pageSize?: number; where?: Prisma.PostWhereInput; select?: Prisma.PostSelect<DefaultArgs>; },
|
||||
staff?: UserProfile,
|
||||
clientIp?: string,
|
||||
) {
|
||||
if (!args.where) args.where = {};
|
||||
args.where.OR = await this.preFilter(args.where.OR, staff);
|
||||
return this.wrapResult(super.findManyWithPagination(args), async (result) => {
|
||||
const { items } = result;
|
||||
await Promise.all(
|
||||
items.map(async (item) => {
|
||||
await setPostRelation({ data: item, staff, clientIp });
|
||||
await this.setPerms(item, staff);
|
||||
}),
|
||||
);
|
||||
return { ...result, items };
|
||||
});
|
||||
}
|
||||
protected async setPerms(data: Post, staff?: UserProfile) {
|
||||
if (!staff) return;
|
||||
const perms: ResPerm = {
|
||||
|
|
|
@ -61,9 +61,7 @@ export async function setPostRelation(params: {
|
|||
readed,
|
||||
readedCount,
|
||||
liked,
|
||||
// limitedComments,
|
||||
commentsCount,
|
||||
// trouble
|
||||
});
|
||||
// console.log('data', data);
|
||||
return data; // 明确返回修改后的数据
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { PostState } from "@nice/common";
|
||||
|
||||
export const BADGE_STYLES = {
|
||||
priority: {
|
||||
high: "bg-red-100 text-red-800",
|
||||
medium: "bg-yellow-100 text-yellow-800",
|
||||
low: "bg-green-100 text-green-800",
|
||||
},
|
||||
category: {
|
||||
complaint: "bg-orange-100 text-orange-800",
|
||||
suggestion: "bg-blue-100 text-blue-800",
|
||||
request: "bg-purple-100 text-purple-800",
|
||||
feedback: "bg-teal-100 text-teal-800",
|
||||
},
|
||||
status: {
|
||||
[PostState.PENDING]: "bg-yellow-100 text-yellow-800",
|
||||
[PostState.PROCESSING]: "bg-blue-100 text-blue-800",
|
||||
[PostState.RESOLVED]: "bg-green-100 text-green-800",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const getBadgeStyle = (
|
||||
type: keyof typeof BADGE_STYLES,
|
||||
value: string
|
||||
): string => {
|
||||
return (
|
||||
BADGE_STYLES[type][value as keyof (typeof BADGE_STYLES)[typeof type]] ||
|
||||
"bg-gray-100 text-gray-800"
|
||||
);
|
||||
};
|
|
@ -2,64 +2,21 @@ import { useState } from "react";
|
|||
import { Input, Button, Card, Steps, Tag, Spin, message } from "antd";
|
||||
import { SearchOutlined, SafetyCertificateOutlined } from "@ant-design/icons";
|
||||
import ProgressHeader from "./ProgressHeader";
|
||||
import { api } from "@nice/client";
|
||||
import { LetterBadge } from "@web/src/components/models/post/LetterBadge";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
interface FeedbackStatus {
|
||||
status: "pending" | "processing" | "resolved";
|
||||
ticketId: string;
|
||||
submittedDate: string;
|
||||
lastUpdate: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { Step } = Steps;
|
||||
|
||||
export default function LetterProgressPage() {
|
||||
const [feedbackId, setFeedbackId] = useState("");
|
||||
const [status, setStatus] = useState<FeedbackStatus | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const validateInput = () => {
|
||||
if (!feedbackId.trim()) {
|
||||
setError("请输入有效的问题编号");
|
||||
return false;
|
||||
const [letterId, setLetterId] = useState<string | undefined>();
|
||||
const { data } = api.post.findFirst.useQuery({
|
||||
where: {
|
||||
id: letterId
|
||||
}
|
||||
if (!/^USAF-\d{4}-\d{4}$/.test(feedbackId)) {
|
||||
setError("问题编号格式不正确,应为USAF-YYYY-NNNN");
|
||||
return false;
|
||||
}
|
||||
setError("");
|
||||
return true;
|
||||
};
|
||||
}, { enabled: Boolean(letterId) })
|
||||
|
||||
const mockLookup = () => {
|
||||
if (!validateInput()) return;
|
||||
|
||||
setLoading(true);
|
||||
setTimeout(() => {
|
||||
setStatus({
|
||||
status: "processing",
|
||||
ticketId: feedbackId,
|
||||
submittedDate: "2025-01-15",
|
||||
lastUpdate: "2025-01-21",
|
||||
title: "Aircraft Maintenance Schedule Inquiry",
|
||||
});
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case "pending":
|
||||
return "orange";
|
||||
case "processing":
|
||||
return "blue";
|
||||
case "resolved":
|
||||
return "green";
|
||||
default:
|
||||
return "gray";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -75,40 +32,25 @@ export default function LetterProgressPage() {
|
|||
<SearchOutlined className=" text-secondary-300" />
|
||||
}
|
||||
size="large"
|
||||
value={feedbackId}
|
||||
onChange={(e) => setFeedbackId(e.target.value)}
|
||||
value={letterId}
|
||||
onChange={(e) => setLetterId(e.target.value)}
|
||||
placeholder="请输入信件编码查询处理状态"
|
||||
status={error ? "error" : ""}
|
||||
className="border border-gray-300"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
loading={loading}
|
||||
onClick={mockLookup}
|
||||
>
|
||||
查询
|
||||
</Button>
|
||||
</div>
|
||||
{error && (
|
||||
<p className="text-red-600 text-sm">{error}</p>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
{/* Results Section */}
|
||||
{status && (
|
||||
{data && (
|
||||
<Card>
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between border-b pb-4">
|
||||
<h2 className="text-xl font-semibold text-[#003366]">
|
||||
Ticket Details
|
||||
处理进度
|
||||
</h2>
|
||||
<Tag
|
||||
color={getStatusColor(status.status)}
|
||||
className="font-bold uppercase">
|
||||
{status.status}
|
||||
</Tag>
|
||||
<LetterBadge type="state" value={data?.state}></LetterBadge>
|
||||
</div>
|
||||
|
||||
{/* Details Grid */}
|
||||
|
@ -118,31 +60,31 @@ export default function LetterProgressPage() {
|
|||
Ticket ID
|
||||
</p>
|
||||
<p className="font-medium text-[#003366]">
|
||||
{status.ticketId}
|
||||
{data.id}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">
|
||||
Submitted Date
|
||||
提交日期
|
||||
</p>
|
||||
<p className="font-medium text-[#003366]">
|
||||
{status.submittedDate}
|
||||
{dayjs(data.createdAt).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">
|
||||
Last Update
|
||||
最后更新
|
||||
</p>
|
||||
<p className="font-medium text-[#003366]">
|
||||
{status.lastUpdate}
|
||||
{dayjs(data.updatedAt).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">
|
||||
Subject
|
||||
标题
|
||||
</p>
|
||||
<p className="font-medium text-[#003366]">
|
||||
{status.title}
|
||||
{data.title}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -151,9 +93,9 @@ export default function LetterProgressPage() {
|
|||
<div className="mt-8">
|
||||
<Steps
|
||||
current={
|
||||
status.status === "pending"
|
||||
data.state === "pending"
|
||||
? 0
|
||||
: status.status === "processing"
|
||||
: data.state === "processing"
|
||||
? 1
|
||||
: 2
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
import { PostState, PostStateLabels } from '@nice/common';
|
||||
import {
|
||||
ExclamationCircleOutlined,
|
||||
BulbOutlined,
|
||||
QuestionCircleOutlined,
|
||||
CommentOutlined,
|
||||
ClockCircleOutlined,
|
||||
SyncOutlined,
|
||||
CheckCircleOutlined,
|
||||
TagOutlined,
|
||||
} from '@ant-design/icons';
|
||||
|
||||
export const BADGE_STYLES = {
|
||||
category: {
|
||||
complaint: {
|
||||
bg: "bg-gradient-to-r from-orange-50 to-orange-100",
|
||||
text: "text-orange-800",
|
||||
border: "border-orange-200",
|
||||
icon: <ExclamationCircleOutlined className="text-orange-500" />,
|
||||
hover: "hover:from-orange-100 hover:to-orange-200",
|
||||
},
|
||||
suggestion: {
|
||||
bg: "bg-gradient-to-r from-blue-50 to-blue-100",
|
||||
text: "text-blue-800",
|
||||
border: "border-blue-200",
|
||||
icon: <BulbOutlined className="text-blue-500" />,
|
||||
hover: "hover:from-blue-100 hover:to-blue-200",
|
||||
},
|
||||
request: {
|
||||
bg: "bg-gradient-to-r from-purple-50 to-purple-100",
|
||||
text: "text-purple-800",
|
||||
border: "border-purple-200",
|
||||
icon: <QuestionCircleOutlined className="text-purple-500" />,
|
||||
hover: "hover:from-purple-100 hover:to-purple-200",
|
||||
},
|
||||
feedback: {
|
||||
bg: "bg-gradient-to-r from-teal-50 to-teal-100",
|
||||
text: "text-teal-800",
|
||||
border: "border-teal-200",
|
||||
icon: <CommentOutlined className="text-teal-500" />,
|
||||
hover: "hover:from-teal-100 hover:to-teal-200",
|
||||
},
|
||||
},
|
||||
state: {
|
||||
[PostState.PENDING]: {
|
||||
bg: "bg-gradient-to-r from-yellow-50 to-yellow-100",
|
||||
text: "text-yellow-800",
|
||||
border: "border-yellow-200",
|
||||
icon: <ClockCircleOutlined className="text-yellow-500" />,
|
||||
hover: "hover:from-yellow-100 hover:to-yellow-200",
|
||||
},
|
||||
[PostState.PROCESSING]: {
|
||||
bg: "bg-gradient-to-r from-blue-50 to-blue-100",
|
||||
text: "text-blue-800",
|
||||
border: "border-blue-200",
|
||||
icon: <SyncOutlined className="text-blue-500" spin />,
|
||||
hover: "hover:from-blue-100 hover:to-blue-200",
|
||||
},
|
||||
[PostState.RESOLVED]: {
|
||||
bg: "bg-gradient-to-r from-green-50 to-green-100",
|
||||
text: "text-green-800",
|
||||
border: "border-green-200",
|
||||
icon: <CheckCircleOutlined className="text-green-500" />,
|
||||
hover: "hover:from-green-100 hover:to-green-200",
|
||||
},
|
||||
},
|
||||
tag: {
|
||||
default: {
|
||||
bg: "bg-gradient-to-r from-gray-50 to-gray-100",
|
||||
text: "text-gray-800",
|
||||
border: "border-gray-200",
|
||||
icon: <TagOutlined className="text-gray-500" />,
|
||||
hover: "hover:from-gray-100 hover:to-gray-200",
|
||||
}
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const getBadgeStyle = (
|
||||
type: keyof typeof BADGE_STYLES,
|
||||
value: string
|
||||
) => {
|
||||
const style = type === 'tag'
|
||||
? BADGE_STYLES.tag.default
|
||||
: BADGE_STYLES[type][value as keyof (typeof BADGE_STYLES)[typeof type]] || {
|
||||
bg: "bg-gradient-to-r from-gray-50 to-gray-100",
|
||||
text: "text-gray-800",
|
||||
border: "border-gray-200",
|
||||
icon: <TagOutlined className="text-gray-500" />,
|
||||
hover: "hover:from-gray-100 hover:to-gray-200",
|
||||
};
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
export function LetterBadge({
|
||||
type,
|
||||
value,
|
||||
className = "",
|
||||
}: {
|
||||
type: "category" | "state" | "tag";
|
||||
value: string;
|
||||
className?: string;
|
||||
}) {
|
||||
if (!value) return null;
|
||||
|
||||
const style = getBadgeStyle(type, value);
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`
|
||||
inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-medium
|
||||
${style.bg} ${style.text} ${style.hover}
|
||||
border ${style.border}
|
||||
shadow-sm backdrop-blur-sm
|
||||
transition-all duration-300 ease-out
|
||||
hover:shadow-md hover:-translate-y-0.5
|
||||
${className}
|
||||
`}>
|
||||
{style.icon}
|
||||
<span className="tracking-wide">
|
||||
{type === 'state' ? PostStateLabels[value] : value}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
|
@ -9,12 +9,10 @@ import {
|
|||
SendOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Button, Typography, Space, Tooltip } from "antd";
|
||||
import toast from "react-hot-toast";
|
||||
import { useState } from "react";
|
||||
import { getBadgeStyle } from "@web/src/app/main/letter/list/utils";
|
||||
import { PostDto } from "@nice/common";
|
||||
import { PostDto, PostStateLabels } from "@nice/common";
|
||||
import dayjs from "dayjs";
|
||||
import PostLikeButton from "./detail/PostHeader/PostLikeButton";
|
||||
import { LetterBadge } from "./LetterBadge";
|
||||
const { Title, Paragraph, Text } = Typography;
|
||||
|
||||
interface LetterCardProps {
|
||||
|
@ -22,78 +20,104 @@ interface LetterCardProps {
|
|||
}
|
||||
|
||||
export function LetterCard({ letter }: LetterCardProps) {
|
||||
|
||||
|
||||
return (
|
||||
<div className="w-full p-4 bg-white transition-all duration-300 ease-in-out group">
|
||||
<div className="flex flex-col gap-3">
|
||||
{/* Title & Priority */}
|
||||
<div onClick={() => {
|
||||
window.open(`/${letter.id}/detail`)
|
||||
}}
|
||||
className=" cursor-pointer w-full p-6 bg-white rounded-xl group relative overflow-hidden duration-300 hover:-translate-y-1 transition-all ease-in-out "
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex justify-between items-start">
|
||||
<Title level={4} className="!mb-0 flex-1">
|
||||
<Title level={4} className="!mb-0 flex-1 font-serif tracking-tight text-gray-800">
|
||||
<a
|
||||
href={`/${letter.id}/detail`}
|
||||
target="_blank"
|
||||
className="text-primary transition-all duration-300 relative
|
||||
before:absolute before:bottom-0 before:left-0 before:w-0 before:h-[2px] before:bg-primary-600
|
||||
group-hover:before:w-full before:transition-all before:duration-300
|
||||
group-hover:text-primary-600 group-hover:scale-105 group-hover:drop-shadow-md">
|
||||
|
||||
className="text-primary hover:text-primary-600 transition-colors duration-200 hover:underline">
|
||||
{letter.title}
|
||||
</a>
|
||||
</Title>
|
||||
</div>
|
||||
|
||||
{/* Meta Info */}
|
||||
<div className="flex justify-between items-center text-sm text-secondary">
|
||||
<Space size="middle">
|
||||
<Space>
|
||||
<UserOutlined className=" text-secondary-400"></UserOutlined>
|
||||
<Text>
|
||||
<div className="flex justify-between items-center text-sm text-gray-500">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserOutlined className="text-secondary-400 text-base" />
|
||||
<Text className="text-gray-600 font-medium">
|
||||
{letter.author?.showname || '匿名用户'}
|
||||
</Text>
|
||||
</Space>
|
||||
<Space>
|
||||
<BankOutlined className="text-secondary-400" />
|
||||
<Text>{letter.receivers.map(item => item.department?.name).toString()}</Text>
|
||||
</Space>
|
||||
<Space>
|
||||
<SendOutlined className=" text-secondary-400"></SendOutlined>
|
||||
<Text >
|
||||
{letter.receivers.map(item => item.showname).toString()}
|
||||
</Text>
|
||||
</Space>
|
||||
</Space>
|
||||
<Space>
|
||||
<CalendarOutlined className="text-secondary-400" />
|
||||
<Text type="secondary">
|
||||
</div>
|
||||
|
||||
{letter.receivers.some(item => item.department?.name) && (
|
||||
<div className="flex items-center gap-2">
|
||||
<BankOutlined className="text-secondary-400 text-base" />
|
||||
<Tooltip title={letter.receivers.map(item => item.department?.name).filter(Boolean).join(', ')}>
|
||||
<Text className="text-gray-600">
|
||||
{letter.receivers
|
||||
.map(item => item.department?.name)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.join('、')}
|
||||
{letter.receivers.filter(item => item.department?.name).length > 2 && ' 等'}
|
||||
</Text>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{letter.receivers.some(item => item.showname) && (
|
||||
<div className="flex items-center gap-2">
|
||||
<SendOutlined className="text-secondary-400 text-base" />
|
||||
<Tooltip title={letter.receivers.map(item => item.showname).filter(Boolean).join(', ')}>
|
||||
<Text className="text-gray-600">
|
||||
{letter.receivers
|
||||
.map(item => item.showname)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.join('、')}
|
||||
{letter.receivers.filter(item => item.showname).length > 2 && ' 等'}
|
||||
</Text>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<CalendarOutlined className="text-secondary-400 text-base" />
|
||||
<Text className="text-gray-500">
|
||||
{dayjs(letter.createdAt).format("YYYY-MM-DD")}
|
||||
</Text>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Preview */}
|
||||
{letter.content && (
|
||||
<div className="flex items-start gap-2">
|
||||
<FileTextOutlined className="text-gray-400 mt-1" />
|
||||
<Paragraph
|
||||
ellipsis={{ rows: 2 }}
|
||||
className="!mb-3 text-gray-600 flex-1">
|
||||
{letter.content}
|
||||
</Paragraph>
|
||||
</div>
|
||||
<Paragraph
|
||||
ellipsis={{ rows: 2 }}
|
||||
className="!mb-4 text-gray-600 flex-1 leading-relaxed text-sm font-sans">
|
||||
{letter.content}
|
||||
</Paragraph>
|
||||
)}
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<LetterBadge type="state" value={letter.state} />
|
||||
{letter.meta.tags.map(tag => (
|
||||
<LetterBadge key={tag} type="tag" value={tag} />
|
||||
))}
|
||||
</div>
|
||||
{/* Badges & Interactions */}
|
||||
<div className="flex justify-between items-center">
|
||||
<Space size="small" wrap className="flex-1">
|
||||
<Badge type="category" value={"11"} />
|
||||
<Badge type="status" value={"22"} />
|
||||
</Space>
|
||||
<div className="flex justify-between items-center ">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{letter.terms.map(term => (
|
||||
<LetterBadge key={term.name} type="category" value={term.name} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-1 text-gray-500">
|
||||
<EyeOutlined className="text-lg" />
|
||||
<span className="text-sm">{letter.views}</span>
|
||||
</div>
|
||||
<Button
|
||||
type="default"
|
||||
shape="round"
|
||||
icon={<EyeOutlined />}
|
||||
>
|
||||
{letter.views}
|
||||
</Button>
|
||||
<PostLikeButton post={letter as any}></PostLikeButton>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -101,27 +125,3 @@ export function LetterCard({ letter }: LetterCardProps) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Badge({
|
||||
type,
|
||||
value,
|
||||
className = "",
|
||||
}: {
|
||||
type: "priority" | "category" | "status";
|
||||
value: string;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
value && (
|
||||
<span
|
||||
className={`
|
||||
inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
|
||||
${getBadgeStyle(type, value)}
|
||||
transition-all duration-200 ease-in-out transform hover:scale-105
|
||||
${className}
|
||||
`}>
|
||||
{value?.toUpperCase()}
|
||||
</span>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { PostDto, VisitType } from "@nice/common";
|
||||
import { useVisitor } from "@nice/client";
|
||||
import { useContext } from "react";
|
||||
import { PostDetailContext } from "../context/PostDetailContext";
|
||||
import { Button, Tooltip } from "antd";
|
||||
import { LikeFilled, LikeOutlined } from "@ant-design/icons";
|
||||
import { useAuth } from "@web/src/providers/auth-provider";
|
||||
|
@ -37,17 +35,14 @@ export default function PostLikeButton({ post }: { post: PostDto }) {
|
|||
<Button
|
||||
type={post?.liked ? "primary" : "default"}
|
||||
shape="round"
|
||||
size="small"
|
||||
ghost={post?.liked}
|
||||
icon={post?.liked ? <LikeFilled /> : <LikeOutlined />}
|
||||
onClick={likeThisPost}
|
||||
className={`
|
||||
flex items-center gap-1 px-3 transform transition-all duration-300
|
||||
hover:scale-105 hover:shadow-md
|
||||
${post?.liked ? "bg-blue-500 hover:bg-blue-600" : "hover:border-blue-500 hover:text-blue-500"}
|
||||
`}>
|
||||
<span className={post?.liked ? "text-white" : ""}>
|
||||
{post?.likes}
|
||||
</span>
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
likeThisPost()
|
||||
}}
|
||||
>
|
||||
{post?.likes}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
|
@ -135,7 +135,7 @@ export type PostDto = Post & {
|
|||
liked: boolean;
|
||||
readedCount: number;
|
||||
commentsCount: number;
|
||||
term: TermDto;
|
||||
terms: TermDto[];
|
||||
author: StaffDto | undefined;
|
||||
receivers: StaffDto[];
|
||||
resources: Resource[];
|
||||
|
|
Loading…
Reference in New Issue