01240017
This commit is contained in:
parent
910371e9d4
commit
4600362e4d
|
@ -33,8 +33,8 @@
|
||||||
"@nice/client": "workspace:^",
|
"@nice/client": "workspace:^",
|
||||||
"@nice/common": "workspace:^",
|
"@nice/common": "workspace:^",
|
||||||
"@nice/iconer": "workspace:^",
|
"@nice/iconer": "workspace:^",
|
||||||
"@nice/ui": "workspace:^",
|
|
||||||
"@nice/theme": "workspace:^",
|
"@nice/theme": "workspace:^",
|
||||||
|
"@nice/ui": "workspace:^",
|
||||||
"@tanstack/query-async-storage-persister": "^5.51.9",
|
"@tanstack/query-async-storage-persister": "^5.51.9",
|
||||||
"@tanstack/react-query": "^5.51.21",
|
"@tanstack/react-query": "^5.51.21",
|
||||||
"@tanstack/react-query-persist-client": "^5.51.9",
|
"@tanstack/react-query-persist-client": "^5.51.9",
|
||||||
|
@ -70,6 +70,7 @@
|
||||||
"superjson": "^2.2.1",
|
"superjson": "^2.2.1",
|
||||||
"swiper": "^11.2.1",
|
"swiper": "^11.2.1",
|
||||||
"tailwind-merge": "^2.6.0",
|
"tailwind-merge": "^2.6.0",
|
||||||
|
"usehooks-ts": "^3.1.0",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"yjs": "^13.6.20",
|
"yjs": "^13.6.20",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
|
|
|
@ -1,20 +1,40 @@
|
||||||
import { SearchFilters } from "./SearchFilter";
|
import { SearchFilters } from "./SearchFilter";
|
||||||
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
|
|
||||||
|
const handleSearch = (value: string) => {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFilterChange = () => {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className=" bg-gradient-to-r from-primary to-primary-50 p-6">
|
<header className="bg-gradient-to-r from-primary to-primary-50 p-6">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
<h1 className="text-3xl font-bold text-white">公开信件列表</h1>
|
<h1 className="text-3xl font-bold text-white">公开信件列表</h1>
|
||||||
<div className="mt-4 text-blue-50">
|
<div className="mt-4 text-blue-50">
|
||||||
<p className="text-base opacity-90">
|
<p className="text-base opacity-90">
|
||||||
服务宗旨:畅通官兵诉求渠道 • 促进部队建设发展 • 提升单位战斗力
|
服务宗旨:畅通诉求渠道 • 促进建设发展 • 提升单位战斗力
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-2 text-sm opacity-80 flex gap-6">
|
<div className="mt-2 text-sm opacity-80 flex flex-wrap gap-x-6 gap-y-2">
|
||||||
<span>实时跟踪反馈进度</span>
|
<span>实时跟踪反馈进度</span>
|
||||||
<span>保障信息传递安全</span>
|
<span>保障信息传递安全</span>
|
||||||
<span>高效解决实际问题</span>
|
<span>高效解决实际问题</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<SearchFilters className="mt-4"></SearchFilters>
|
<SearchFilters
|
||||||
|
className="mt-4"
|
||||||
|
searchTerm=""
|
||||||
|
filterCategory={null}
|
||||||
|
filterStatus={null}
|
||||||
|
onSearchChange={handleSearch}
|
||||||
|
onCategoryChange={handleFilterChange}
|
||||||
|
onStatusChange={handleFilterChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
|
import { Form, Input, Select, Spin } from 'antd';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
interface SearchFiltersProps {
|
interface SearchFiltersProps {
|
||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
|
@ -7,8 +9,14 @@ interface SearchFiltersProps {
|
||||||
onCategoryChange: (value: string) => void;
|
onCategoryChange: (value: string) => void;
|
||||||
filterStatus: string;
|
filterStatus: string;
|
||||||
onStatusChange: (value: string) => void;
|
onStatusChange: (value: string) => void;
|
||||||
className?: string
|
className?: string;
|
||||||
|
isLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LoadingIndicator = () => (
|
||||||
|
<Spin size="small" className="ml-2" />
|
||||||
|
);
|
||||||
|
|
||||||
export function SearchFilters({
|
export function SearchFilters({
|
||||||
searchTerm,
|
searchTerm,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
|
@ -16,69 +24,67 @@ export function SearchFilters({
|
||||||
onCategoryChange,
|
onCategoryChange,
|
||||||
filterStatus,
|
filterStatus,
|
||||||
onStatusChange,
|
onStatusChange,
|
||||||
className
|
className,
|
||||||
|
isLoading = false
|
||||||
}: SearchFiltersProps) {
|
}: SearchFiltersProps) {
|
||||||
return (
|
const [form] = Form.useForm();
|
||||||
<div className={`flex flex-col sm:flex-row items-center gap-6 ${className}`}>
|
|
||||||
<div className="flex-1 w-full">
|
// 统一处理表单初始值
|
||||||
<div className="relative">
|
const initialValues = {
|
||||||
<MagnifyingGlassIcon className="h-5 w-5 text-[#041E42] absolute left-4 top-1/2 transform -translate-y-1/2" />
|
search: searchTerm,
|
||||||
<input
|
category: filterCategory,
|
||||||
type="text"
|
status: filterStatus
|
||||||
placeholder="Search by keyword, sender, or unit..."
|
};
|
||||||
className="w-full h-[46px] pl-12 pr-4 rounded-lg
|
|
||||||
bg-white shadow-sm transition-all duration-200
|
useEffect(() => {
|
||||||
placeholder:text-tertiary-400
|
form.setFieldsValue(initialValues);
|
||||||
focus:outline-none focus:border-[#00308F] focus:ring-2 focus:ring-[#00308F]/20"
|
}, [searchTerm, filterCategory, filterStatus, form]);
|
||||||
value={searchTerm}
|
|
||||||
onChange={(e) => onSearchChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<FilterDropdowns
|
|
||||||
filterCategory={filterCategory}
|
|
||||||
onCategoryChange={onCategoryChange}
|
|
||||||
filterStatus={filterStatus}
|
|
||||||
onStatusChange={onStatusChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FilterDropdowns({
|
|
||||||
filterCategory,
|
|
||||||
onCategoryChange,
|
|
||||||
filterStatus,
|
|
||||||
onStatusChange,
|
|
||||||
}: Pick<SearchFiltersProps, 'filterCategory' | 'onCategoryChange' | 'filterStatus' | 'onStatusChange'>) {
|
|
||||||
const selectClassName = `min-w-[160px] h-[46px] px-4 rounded-lg
|
|
||||||
bg-white shadow-sm transition-all duration-200
|
|
||||||
text-[#041E42] font-medium
|
|
||||||
focus:outline-none focus:border-[#00308F] focus:ring-2 focus:ring-[#00308F]/20
|
|
||||||
hover:border-[#00308F]`;
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col sm:flex-row gap-4">
|
<Form
|
||||||
<select
|
form={form}
|
||||||
className={selectClassName}
|
layout="vertical"
|
||||||
value={filterCategory}
|
className={className}
|
||||||
onChange={(e) => onCategoryChange(e.target.value)}
|
initialValues={initialValues}
|
||||||
>
|
>
|
||||||
<option value="all">All Categories</option>
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<option value="complaint">Complaints</option>
|
<Form.Item name="search" noStyle>
|
||||||
<option value="suggestion">Suggestions</option>
|
<Input
|
||||||
<option value="request">Requests</option>
|
prefix={<SearchOutlined />}
|
||||||
<option value="feedback">Feedback</option>
|
placeholder="搜索关键词、发件人或单位..."
|
||||||
</select>
|
onChange={(e) => onSearchChange(e.target.value)}
|
||||||
<select
|
allowClear
|
||||||
className={selectClassName}
|
suffix={isLoading ? <LoadingIndicator /> : null}
|
||||||
value={filterStatus}
|
/>
|
||||||
onChange={(e) => onStatusChange(e.target.value)}
|
</Form.Item>
|
||||||
>
|
|
||||||
<option value="all">All Status</option>
|
<Form.Item name="category" noStyle>
|
||||||
<option value="pending">Pending</option>
|
<Select
|
||||||
<option value="in-progress">In Progress</option>
|
className="w-full"
|
||||||
<option value="resolved">Resolved</option>
|
onChange={onCategoryChange}
|
||||||
</select>
|
options={[
|
||||||
|
{ value: 'all', label: '所有分类' },
|
||||||
|
{ value: 'complaint', label: '投诉' },
|
||||||
|
{ value: 'suggestion', label: '建议' },
|
||||||
|
{ value: 'request', label: '请求' },
|
||||||
|
{ value: 'feedback', label: '反馈' }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="status" noStyle>
|
||||||
|
<Select
|
||||||
|
className="w-full"
|
||||||
|
onChange={onStatusChange}
|
||||||
|
options={[
|
||||||
|
{ value: 'all', label: '所有状态' },
|
||||||
|
{ value: 'pending', label: '待处理' },
|
||||||
|
{ value: 'in-progress', label: '处理中' },
|
||||||
|
{ value: 'resolved', label: '已解决' }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { Input, Button, Card, Steps, Tag, Spin, message } from 'antd'
|
||||||
|
import { SearchOutlined, SafetyCertificateOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
interface FeedbackStatus {
|
interface FeedbackStatus {
|
||||||
status: 'pending' | 'in-progress' | 'resolved'
|
status: 'pending' | 'in-progress' | 'resolved'
|
||||||
|
@ -8,111 +10,164 @@ interface FeedbackStatus {
|
||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { Step } = Steps
|
||||||
|
|
||||||
export default function LetterProgressPage() {
|
export default function LetterProgressPage() {
|
||||||
const [feedbackId, setFeedbackId] = useState('')
|
const [feedbackId, setFeedbackId] = useState('')
|
||||||
const [status, setStatus] = useState<FeedbackStatus | null>(null)
|
const [status, setStatus] = useState<FeedbackStatus | null>(null)
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [error, setError] = useState('')
|
||||||
|
|
||||||
|
const validateInput = () => {
|
||||||
|
if (!feedbackId.trim()) {
|
||||||
|
setError('请输入有效的问题编号')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!/^USAF-\d{4}-\d{4}$/.test(feedbackId)) {
|
||||||
|
setError('问题编号格式不正确,应为USAF-YYYY-NNNN')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
setError('')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Mock data - In production this would come from an API
|
|
||||||
const mockLookup = () => {
|
const mockLookup = () => {
|
||||||
|
if (!validateInput()) return
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
|
setTimeout(() => {
|
||||||
setStatus({
|
setStatus({
|
||||||
status: 'in-progress',
|
status: 'in-progress',
|
||||||
ticketId: 'USAF-2025-0123',
|
ticketId: feedbackId,
|
||||||
submittedDate: '2025-01-15',
|
submittedDate: '2025-01-15',
|
||||||
lastUpdate: '2025-01-21',
|
lastUpdate: '2025-01-21',
|
||||||
title: 'Aircraft Maintenance Schedule Inquiry'
|
title: 'Aircraft Maintenance Schedule Inquiry'
|
||||||
})
|
})
|
||||||
|
setLoading(false)
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusColor = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'pending':
|
||||||
|
return 'orange'
|
||||||
|
case 'in-progress':
|
||||||
|
return 'blue'
|
||||||
|
case 'resolved':
|
||||||
|
return 'green'
|
||||||
|
default:
|
||||||
|
return 'gray'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-b from-slate-100 to-slate-200">
|
<div className="min-h-screen bg-white" style={{ fontFamily: 'Arial, sans-serif' }}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<header className="bg-[#00308F] bg-gradient-to-r from-[#00308F] to-[#0353A4] p-6 text-white">
|
<header className="bg-[#003366] p-8 text-white">
|
||||||
<h1 className="text-2xl font-semibold mb-3">
|
<div className="container mx-auto flex items-center">
|
||||||
USAF Feedback Progress Tracking
|
<SafetyCertificateOutlined className="text-4xl mr-4" />
|
||||||
</h1>
|
<div>
|
||||||
<div className="text-lg opacity-90">
|
<h1 className="text-3xl font-bold mb-2">USAF Feedback Tracking System</h1>
|
||||||
<p>请输入您的问题编号以查询处理进度</p>
|
<p className="text-lg">Enter your ticket ID to track progress</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<main className="container mx-auto px-4 py-8">
|
<main className="container mx-auto px-4 py-8">
|
||||||
{/* Search Section */}
|
{/* Search Section */}
|
||||||
<div className="space-y-4 mb-8">
|
<Card className="mb-8 border border-gray-200">
|
||||||
<label
|
<div className="space-y-4">
|
||||||
htmlFor="feedbackId"
|
<label className="block text-lg font-medium text-[#003366]">
|
||||||
className="block text-lg font-medium text-[#1F4E79]"
|
Ticket ID
|
||||||
>
|
|
||||||
Enter Feedback ID
|
|
||||||
</label>
|
</label>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<input
|
<Input
|
||||||
id="feedbackId"
|
prefix={<SearchOutlined className="text-[#003366]" />}
|
||||||
type="text"
|
size="large"
|
||||||
value={feedbackId}
|
value={feedbackId}
|
||||||
onChange={(e) => setFeedbackId(e.target.value)}
|
onChange={(e) => setFeedbackId(e.target.value)}
|
||||||
placeholder="e.g. USAF-2025-0123"
|
placeholder="e.g. USAF-2025-0123"
|
||||||
className="flex-1 p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-[#00538B] focus:border-transparent"
|
status={error ? 'error' : ''}
|
||||||
|
className="border border-gray-300"
|
||||||
/>
|
/>
|
||||||
<button
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
icon={<SearchOutlined />}
|
||||||
|
loading={loading}
|
||||||
onClick={mockLookup}
|
onClick={mockLookup}
|
||||||
className="px-6 py-3 bg-[#00538B] text-white rounded-md hover:bg-[#1F4E79] transition-colors duration-200"
|
style={{ backgroundColor: '#003366', borderColor: '#003366' }}
|
||||||
>
|
>
|
||||||
Track
|
Track
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
{error && <p className="text-red-600 text-sm">{error}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
{/* Results Section */}
|
{/* Results Section */}
|
||||||
{status && (
|
{status && (
|
||||||
<div className="bg-white rounded-lg p-6">
|
<Card>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between border-b pb-4">
|
<div className="flex items-center justify-between border-b pb-4">
|
||||||
<h2 className="text-xl font-semibold text-[#1F4E79]">
|
<h2 className="text-xl font-semibold text-[#003366]">
|
||||||
Feedback Details
|
Ticket Details
|
||||||
</h2>
|
</h2>
|
||||||
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-[#00538B]">
|
<Tag
|
||||||
{status.status.toUpperCase()}
|
color={getStatusColor(status.status)}
|
||||||
</span>
|
className="font-bold uppercase"
|
||||||
|
>
|
||||||
|
{status.status}
|
||||||
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
{/* Details Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-tertiary-300">Ticket ID</p>
|
<p className="text-sm text-gray-600">Ticket ID</p>
|
||||||
<p className="font-medium">{status.ticketId}</p>
|
<p className="font-medium text-[#003366]">{status.ticketId}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-tertiary-300">Submitted Date</p>
|
<p className="text-sm text-gray-600">Submitted Date</p>
|
||||||
<p className="font-medium">{status.submittedDate}</p>
|
<p className="font-medium text-[#003366]">{status.submittedDate}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-tertiary-300">Last Update</p>
|
<p className="text-sm text-gray-600">Last Update</p>
|
||||||
<p className="font-medium">{status.lastUpdate}</p>
|
<p className="font-medium text-[#003366]">{status.lastUpdate}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-tertiary-300">Title</p>
|
<p className="text-sm text-gray-600">Subject</p>
|
||||||
<p className="font-medium">{status.title}</p>
|
<p className="font-medium text-[#003366]">{status.title}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Progress Timeline */}
|
{/* Progress Timeline */}
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<div className="relative">
|
<Steps
|
||||||
<div className="absolute w-full h-1 bg-gray-200 top-4"></div>
|
current={status.status === 'pending' ? 0 : status.status === 'in-progress' ? 1 : 2}
|
||||||
<div className="relative flex justify-between">
|
className="usa-progress"
|
||||||
{['Submitted', 'In Review', 'Resolved'].map((step, index) => (
|
>
|
||||||
<div key={step} className="text-center">
|
<Step
|
||||||
<div className={`w-8 h-8 mx-auto rounded-full flex items-center justify-center ${index <= 1 ? 'bg-[#00538B] text-white' : 'bg-gray-200'
|
title="Submitted"
|
||||||
}`}>
|
description="Ticket received"
|
||||||
{index + 1}
|
icon={<SafetyCertificateOutlined />}
|
||||||
</div>
|
/>
|
||||||
<div className="mt-2 text-sm font-medium">{step}</div>
|
<Step
|
||||||
</div>
|
title="In Progress"
|
||||||
))}
|
description="Under review"
|
||||||
</div>
|
icon={<SafetyCertificateOutlined />}
|
||||||
</div>
|
/>
|
||||||
</div>
|
<Step
|
||||||
|
title="Resolved"
|
||||||
|
description="Ticket completed"
|
||||||
|
icon={<SafetyCertificateOutlined />}
|
||||||
|
/>
|
||||||
|
</Steps>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Card>
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -404,6 +404,9 @@ importers:
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^2.6.0
|
specifier: ^2.6.0
|
||||||
version: 2.6.0
|
version: 2.6.0
|
||||||
|
usehooks-ts:
|
||||||
|
specifier: ^3.1.0
|
||||||
|
version: 3.1.0(react@18.2.0)
|
||||||
uuid:
|
uuid:
|
||||||
specifier: ^10.0.0
|
specifier: ^10.0.0
|
||||||
version: 10.0.0
|
version: 10.0.0
|
||||||
|
@ -6800,6 +6803,12 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
usehooks-ts@3.1.0:
|
||||||
|
resolution: {integrity: sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==}
|
||||||
|
engines: {node: '>=16.15.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17 || ^18
|
||||||
|
|
||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
|
@ -14251,6 +14260,11 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
||||||
|
usehooks-ts@3.1.0(react@18.2.0):
|
||||||
|
dependencies:
|
||||||
|
lodash.debounce: 4.0.8
|
||||||
|
react: 18.2.0
|
||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
util@0.12.5:
|
util@0.12.5:
|
||||||
|
|
Loading…
Reference in New Issue