Caegory seçimi
This commit is contained in:
parent
8d389fc955
commit
9ca2b81a50
6 changed files with 253 additions and 130 deletions
|
|
@ -9,6 +9,7 @@ using Volo.Abp.Application.Dtos;
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Volo.Abp.Domain.Entities;
|
||||||
|
|
||||||
namespace Kurs.Platform.Reports;
|
namespace Kurs.Platform.Reports;
|
||||||
|
|
||||||
|
|
@ -18,15 +19,26 @@ public class ReportAppService : PlatformAppService, IReportAppService
|
||||||
private readonly IRepository<ReportTemplate, Guid> _reportTemplateRepository;
|
private readonly IRepository<ReportTemplate, Guid> _reportTemplateRepository;
|
||||||
private readonly IRepository<ReportGenerated, Guid> _generatedReportRepository;
|
private readonly IRepository<ReportGenerated, Guid> _generatedReportRepository;
|
||||||
private readonly IRepository<ReportParameter, Guid> _reportParameterRepository;
|
private readonly IRepository<ReportParameter, Guid> _reportParameterRepository;
|
||||||
|
private readonly IRepository<ReportCategory, Guid> _reportCategotyRepository;
|
||||||
|
|
||||||
public ReportAppService(
|
public ReportAppService(
|
||||||
IRepository<ReportTemplate, Guid> reportTemplateRepository,
|
IRepository<ReportTemplate, Guid> reportTemplateRepository,
|
||||||
IRepository<ReportGenerated, Guid> generatedReportRepository,
|
IRepository<ReportGenerated, Guid> generatedReportRepository,
|
||||||
IRepository<ReportParameter, Guid> reportParameterRepository)
|
IRepository<ReportParameter, Guid> reportParameterRepository,
|
||||||
|
IRepository<ReportCategory, Guid> reportCategotyRepository
|
||||||
|
)
|
||||||
{
|
{
|
||||||
_reportTemplateRepository = reportTemplateRepository;
|
_reportTemplateRepository = reportTemplateRepository;
|
||||||
_generatedReportRepository = generatedReportRepository;
|
_generatedReportRepository = generatedReportRepository;
|
||||||
_reportParameterRepository = reportParameterRepository;
|
_reportParameterRepository = reportParameterRepository;
|
||||||
|
_reportCategotyRepository = reportCategotyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ReportCategoryDto>> GetCategoriesAsync()
|
||||||
|
{
|
||||||
|
var entity = await _reportCategotyRepository.GetListAsync();
|
||||||
|
|
||||||
|
return ObjectMapper.Map<List<ReportCategory>, List<ReportCategoryDto>>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PagedResultDto<ReportTemplateDto>> GetTemplatesAsync(GetReportTemplatesInput input)
|
public async Task<PagedResultDto<ReportTemplateDto>> GetTemplatesAsync(GetReportTemplatesInput input)
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
|
||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.e9emm6ltkho"
|
"revision": "0.71ce98091og"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,68 @@
|
||||||
import React, { useState, useMemo } from 'react'
|
import React, { useState, useMemo, useEffect } from 'react'
|
||||||
import { TemplateEditor } from '../reports/TemplateEditor'
|
import { TemplateEditor } from '../reports/TemplateEditor'
|
||||||
import { ReportGenerator } from '../reports/ReportGenerator'
|
import { ReportGenerator } from '../reports/ReportGenerator'
|
||||||
import { TemplateCard } from './TemplateCard'
|
import { TemplateCard } from './TemplateCard'
|
||||||
import { Button } from '../ui/Button'
|
import { Button } from '../ui/Button'
|
||||||
import { Input } from '../ui/Input'
|
import { Input } from '../ui/Input'
|
||||||
import { Plus, Search, Filter, FileText, BarChart3 } from 'lucide-react'
|
import { Plus, Search, Filter, FileText, BarChart3 } from 'lucide-react'
|
||||||
import { ReportTemplateDto } from '@/proxy/reports/models'
|
import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models'
|
||||||
import { useReports } from '@/utils/hooks/useReports'
|
import { useReports } from '@/utils/hooks/useReports'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
export const Dashboard: React.FC = () => {
|
export const Dashboard: React.FC = () => {
|
||||||
const { templates, isLoading, createTemplate, updateTemplate, deleteTemplate, generateReport } =
|
const {
|
||||||
useReports()
|
templates,
|
||||||
|
categories,
|
||||||
|
isLoading,
|
||||||
|
createTemplate,
|
||||||
|
updateTemplate,
|
||||||
|
deleteTemplate,
|
||||||
|
generateReport,
|
||||||
|
loadTemplatesByCategory,
|
||||||
|
} = useReports()
|
||||||
|
|
||||||
|
const tumuCategory = useMemo(
|
||||||
|
() => ({
|
||||||
|
id: 'tumu-category',
|
||||||
|
name: 'Tümü',
|
||||||
|
description: '',
|
||||||
|
icon: '📋',
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
const [showEditor, setShowEditor] = useState(false)
|
const [showEditor, setShowEditor] = useState(false)
|
||||||
const [showGenerator, setShowGenerator] = useState(false)
|
const [showGenerator, setShowGenerator] = useState(false)
|
||||||
const [editingTemplate, setEditingTemplate] = useState<ReportTemplateDto | null>(null)
|
const [editingTemplate, setEditingTemplate] = useState<ReportTemplateDto | null>(null)
|
||||||
const [generatingTemplate, setGeneratingTemplate] = useState<ReportTemplateDto | null>(null)
|
const [generatingTemplate, setGeneratingTemplate] = useState<ReportTemplateDto | null>(null)
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
const [selectedCategory, setSelectedCategory] = useState('Tümü')
|
const [selectedCategory, setSelectedCategory] = useState<ReportCategoryDto | null>(null)
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const categories = useMemo(() => {
|
// Create category options with "Tümü" at the top
|
||||||
const cats = ['Tümü', ...new Set(templates.map((t) => t.categoryName))]
|
const categoryOptions = useMemo(() => {
|
||||||
return cats
|
const categoryNames = [tumuCategory, ...categories.map((cat) => cat)]
|
||||||
}, [templates])
|
return categoryNames
|
||||||
|
}, [categories, tumuCategory])
|
||||||
|
|
||||||
|
// Set default category when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedCategory) {
|
||||||
|
setSelectedCategory(tumuCategory)
|
||||||
|
}
|
||||||
|
}, [tumuCategory, selectedCategory])
|
||||||
|
|
||||||
|
// Handle category change
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedCategory) {
|
||||||
|
loadTemplatesByCategory(selectedCategory.name)
|
||||||
|
}
|
||||||
|
}, [selectedCategory, loadTemplatesByCategory])
|
||||||
|
|
||||||
|
// Load templates for default category on mount
|
||||||
|
useEffect(() => {
|
||||||
|
loadTemplatesByCategory('Tümü')
|
||||||
|
}, [])
|
||||||
|
|
||||||
const filteredTemplates = useMemo(() => {
|
const filteredTemplates = useMemo(() => {
|
||||||
return templates.filter((template) => {
|
return templates.filter((template) => {
|
||||||
|
|
@ -31,12 +71,9 @@ export const Dashboard: React.FC = () => {
|
||||||
template.description?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
template.description?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
template.tags.some((tag: any) => tag.toLowerCase().includes(searchQuery.toLowerCase()))
|
template.tags.some((tag: any) => tag.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||||
|
|
||||||
const matchesCategory =
|
return matchesSearch
|
||||||
selectedCategory === 'Tümü' || template.categoryName === selectedCategory
|
|
||||||
|
|
||||||
return matchesSearch && matchesCategory
|
|
||||||
})
|
})
|
||||||
}, [templates, searchQuery, selectedCategory])
|
}, [templates, searchQuery])
|
||||||
|
|
||||||
const handleCreateTemplate = () => {
|
const handleCreateTemplate = () => {
|
||||||
setEditingTemplate(null)
|
setEditingTemplate(null)
|
||||||
|
|
@ -93,7 +130,7 @@ export const Dashboard: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100">
|
<div className="mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center min-h-96">
|
<div className="flex items-center justify-center min-h-96">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
|
|
@ -102,112 +139,138 @@ export const Dashboard: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<div className="flex flex-col lg:flex-row gap-8">
|
||||||
{/* Stats */}
|
{/* Left Sidebar - Categories */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
<div className="lg:w-64 flex-shrink-0 p-4 bg-gray-50">
|
||||||
<div className="bg-white rounded-xl shadow-md p-6 border border-gray-200">
|
<nav className="space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
{categoryOptions.map((category) => {
|
||||||
<div>
|
return (
|
||||||
<p className="text-sm font-medium text-gray-600">Toplam Şablon</p>
|
<button
|
||||||
<p className="text-2xl font-bold text-gray-900">{templates.length}</p>
|
key={category.id}
|
||||||
</div>
|
onClick={() => setSelectedCategory(category)}
|
||||||
<div className="bg-blue-100 p-3 rounded-full">
|
className={`w-full flex items-center space-x-3 px-4 py-3 rounded-lg text-left transition-colors ${
|
||||||
<FileText className="h-6 w-6 text-blue-600" />
|
selectedCategory?.id === category.id
|
||||||
</div>
|
? 'bg-blue-100 text-blue-700'
|
||||||
</div>
|
: 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'
|
||||||
</div>
|
}`}
|
||||||
|
>
|
||||||
<div className="bg-white rounded-xl shadow-md p-6 border border-gray-200">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="flex items-center justify-between">
|
{category.icon && <span className="text-lg">{category.icon}</span>}
|
||||||
<div>
|
<span className="font-medium">{category.name}</span>
|
||||||
<p className="text-sm font-medium text-gray-600">Aktif Kategoriler</p>
|
</div>
|
||||||
<p className="text-2xl font-bold text-gray-900">{categories.length - 1}</p>
|
{category.name !== 'Tümü' && (
|
||||||
</div>
|
<span className="text-sm text-gray-500 ml-2">
|
||||||
<div className="bg-emerald-100 p-3 rounded-full">
|
({templates.filter((t) => t.categoryName === category.name).length})
|
||||||
<Filter className="h-6 w-6 text-emerald-600" />
|
</span>
|
||||||
</div>
|
)}
|
||||||
</div>
|
{category.name === 'Tümü' && (
|
||||||
</div>
|
<span className="text-sm text-gray-500 ml-2">({templates.length})</span>
|
||||||
|
)}
|
||||||
<div className="bg-white rounded-xl shadow-md p-6 border border-gray-200">
|
</button>
|
||||||
<div className="flex items-center justify-between">
|
)
|
||||||
<div>
|
})}
|
||||||
<p className="text-sm font-medium text-gray-600">Toplam Parametre</p>
|
</nav>
|
||||||
<p className="text-2xl font-bold text-gray-900">
|
|
||||||
{templates.reduce((sum, t) => sum + t.parameters.length, 0)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="bg-purple-100 p-3 rounded-full">
|
|
||||||
<BarChart3 className="h-6 w-6 text-purple-600" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filters */}
|
{/* Main Content */}
|
||||||
<div className="bg-white rounded-xl shadow-md p-6 mb-8 border border-gray-200">
|
<div className="flex-1">
|
||||||
<div className="flex flex-col md:flex-row gap-4">
|
<h2 className="text-2xl font-bold text-gray-900 mb-6">
|
||||||
<div className="flex-1">
|
{translate('::App.Forum.Dashboard.Statistics')}
|
||||||
<div className="relative">
|
</h2>
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
|
{/* Stats */}
|
||||||
<Input
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||||
placeholder="Şablon ara..."
|
<div className="bg-white rounded-xl shadow-md p-6 border border-gray-200">
|
||||||
value={searchQuery}
|
<div className="flex items-center justify-between">
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
<div>
|
||||||
className="pl-10"
|
<p className="text-sm font-medium text-gray-600">Toplam Şablon</p>
|
||||||
/>
|
<p className="text-2xl font-bold text-gray-900">{templates.length}</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-blue-100 p-3 rounded-full">
|
||||||
|
<FileText className="h-6 w-6 text-blue-600" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:w-48">
|
<div className="bg-white rounded-xl shadow-md p-6 border border-gray-200">
|
||||||
<select
|
<div className="flex items-center justify-between">
|
||||||
value={selectedCategory}
|
<div>
|
||||||
onChange={(e) => setSelectedCategory(e.target.value)}
|
<p className="text-sm font-medium text-gray-600">Aktif Kategoriler</p>
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
<p className="text-2xl font-bold text-gray-900">{categories.length}</p>
|
||||||
>
|
</div>
|
||||||
{categories.map((category) => (
|
<div className="bg-emerald-100 p-3 rounded-full">
|
||||||
<option key={category} value={category}>
|
<Filter className="h-6 w-6 text-emerald-600" />
|
||||||
{category}
|
</div>
|
||||||
</option>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</select>
|
|
||||||
|
<div className="bg-white rounded-xl shadow-md p-6 border border-gray-200">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-gray-600">Toplam Parametre</p>
|
||||||
|
<p className="text-2xl font-bold text-gray-900">
|
||||||
|
{templates.reduce((sum, t) => sum + t.parameters.length, 0)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-purple-100 p-3 rounded-full">
|
||||||
|
<BarChart3 className="h-6 w-6 text-purple-600" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/* Filters */}
|
||||||
|
<div className="bg-white rounded-xl shadow-md p-6 mb-8 border border-gray-200">
|
||||||
{/* Templates Grid */}
|
<div className="flex flex-col md:flex-row gap-4">
|
||||||
{filteredTemplates.length === 0 ? (
|
<div className="flex-1">
|
||||||
<div className="bg-white rounded-xl shadow-md p-12 border border-gray-200">
|
<div className="relative">
|
||||||
<FileText className="h-16 w-16 text-gray-400 mx-auto mb-4" />
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
|
||||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
<Input
|
||||||
{templates.length === 0 ? 'Henüz şablon oluşturulmamış' : 'Şablon bulunamadı'}
|
placeholder="Şablon ara..."
|
||||||
</h3>
|
value={searchQuery}
|
||||||
<p className="text-gray-500 mb-6">
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
{templates.length === 0
|
className="pl-10"
|
||||||
? 'İlk rapor şablonunuzu oluşturarak başlayın.'
|
/>
|
||||||
: 'Arama kriterlerinize uygun şablon bulunamadı.'}
|
</div>
|
||||||
</p>
|
</div>
|
||||||
{templates.length === 0 && (
|
|
||||||
<Button onClick={handleCreateTemplate}>
|
<Button onClick={handleCreateTemplate}>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
İlk Şablonu Oluştur
|
Yeni Şablon
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
{/* Templates Grid */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
{filteredTemplates.length === 0 ? (
|
||||||
{filteredTemplates.map((template) => (
|
<div className="bg-white rounded-xl shadow-md p-12 border border-gray-200">
|
||||||
<TemplateCard
|
<FileText className="h-16 w-16 text-gray-400 mx-auto mb-4" />
|
||||||
key={template.id}
|
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||||
template={template}
|
{templates.length === 0 ? 'Henüz şablon oluşturulmamış' : 'Şablon bulunamadı'}
|
||||||
onEdit={handleEditTemplate}
|
</h3>
|
||||||
onDelete={handleDeleteTemplate}
|
<p className="text-gray-500 mb-6">
|
||||||
onGenerate={handleGenerateReport}
|
{templates.length === 0
|
||||||
/>
|
? 'İlk rapor şablonunuzu oluşturarak başlayın.'
|
||||||
))}
|
: 'Arama kriterlerinize uygun şablon bulunamadı.'}
|
||||||
</div>
|
</p>
|
||||||
)}
|
{templates.length === 0 && (
|
||||||
</main>
|
<Button onClick={handleCreateTemplate}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
İlk Şablonu Oluştur
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{filteredTemplates.map((template) => (
|
||||||
|
<TemplateCard
|
||||||
|
key={template.id}
|
||||||
|
template={template}
|
||||||
|
onEdit={handleEditTemplate}
|
||||||
|
onDelete={handleDeleteTemplate}
|
||||||
|
onGenerate={handleGenerateReport}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Modals */}
|
{/* Modals */}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
export type ReportParameterType = 'text' | 'number' | 'date' | 'select' | 'checkbox'
|
export type ReportParameterType = 'text' | 'number' | 'date' | 'select' | 'checkbox'
|
||||||
|
|
||||||
|
export interface ReportCategoryDto {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
icon?: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface ReportParameterDto {
|
export interface ReportParameterDto {
|
||||||
id: string
|
id: string
|
||||||
reportTemplateId: string
|
reportTemplateId: string
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ import {
|
||||||
ReportGeneratedDto,
|
ReportGeneratedDto,
|
||||||
CreateReportTemplateDto,
|
CreateReportTemplateDto,
|
||||||
UpdateReportTemplateDto,
|
UpdateReportTemplateDto,
|
||||||
ReportGenerateDto, // backend'deki GenerateReportDto (templateId + parameters)
|
ReportGenerateDto,
|
||||||
|
ReportCategoryDto,
|
||||||
|
GetReportTemplatesInput, // backend'deki GenerateReportDto (templateId + parameters)
|
||||||
} from '@/proxy/reports/models'
|
} from '@/proxy/reports/models'
|
||||||
import apiService from './api.service'
|
import apiService from './api.service'
|
||||||
import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy'
|
import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy'
|
||||||
|
|
@ -16,8 +18,17 @@ export interface ReportsData {
|
||||||
export class ReportsService {
|
export class ReportsService {
|
||||||
apiName = 'Default'
|
apiName = 'Default'
|
||||||
|
|
||||||
|
getCategories = () =>
|
||||||
|
apiService.fetchData<ReportCategoryDto[]>(
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
url: '/api/app/report/categories',
|
||||||
|
},
|
||||||
|
{ apiName: this.apiName },
|
||||||
|
)
|
||||||
|
|
||||||
// TEMPLATES
|
// TEMPLATES
|
||||||
getTemplates = (input: PagedAndSortedResultRequestDto) =>
|
getTemplates = (input: GetReportTemplatesInput) =>
|
||||||
apiService.fetchData<PagedResultDto<ReportTemplateDto>, PagedAndSortedResultRequestDto>(
|
apiService.fetchData<PagedResultDto<ReportTemplateDto>, PagedAndSortedResultRequestDto>(
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReportGeneratedDto, ReportTemplateDto } from '@/proxy/reports/models'
|
import { ReportGeneratedDto, ReportTemplateDto, ReportCategoryDto } from '@/proxy/reports/models'
|
||||||
import ReportsService from '@/services/reports.service'
|
import ReportsService from '@/services/reports.service'
|
||||||
import { useState, useCallback, useEffect } from 'react'
|
import { useState, useCallback, useEffect } from 'react'
|
||||||
|
|
||||||
|
|
@ -7,12 +7,14 @@ const reportsService = new ReportsService()
|
||||||
interface ReportData {
|
interface ReportData {
|
||||||
templates: ReportTemplateDto[]
|
templates: ReportTemplateDto[]
|
||||||
generatedReports: ReportGeneratedDto[]
|
generatedReports: ReportGeneratedDto[]
|
||||||
|
categories: ReportCategoryDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useReports = () => {
|
export const useReports = () => {
|
||||||
const [data, setData] = useState<ReportData>({
|
const [data, setData] = useState<ReportData>({
|
||||||
templates: [],
|
templates: [],
|
||||||
generatedReports: [],
|
generatedReports: [],
|
||||||
|
categories: [],
|
||||||
})
|
})
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
|
|
@ -22,22 +24,26 @@ export const useReports = () => {
|
||||||
try {
|
try {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||||
|
|
||||||
const [templatesResponse, generatedReportsResponse] = await Promise.all([
|
const [templatesResponse, generatedReportsResponse, categoriesResponse] = await Promise.all(
|
||||||
reportsService.getTemplates({
|
[
|
||||||
sorting: '',
|
reportsService.getTemplates({
|
||||||
skipCount: 0,
|
sorting: '',
|
||||||
maxResultCount: 1000,
|
skipCount: 0,
|
||||||
}),
|
maxResultCount: 1000,
|
||||||
reportsService.getGeneratedReports({
|
}),
|
||||||
sorting: '',
|
reportsService.getGeneratedReports({
|
||||||
skipCount: 0,
|
sorting: '',
|
||||||
maxResultCount: 1000,
|
skipCount: 0,
|
||||||
}),
|
maxResultCount: 1000,
|
||||||
])
|
}),
|
||||||
|
reportsService.getCategories(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
setData({
|
setData({
|
||||||
templates: templatesResponse.data.items || [],
|
templates: templatesResponse.data.items || [],
|
||||||
generatedReports: generatedReportsResponse.data.items || [],
|
generatedReports: generatedReportsResponse.data.items || [],
|
||||||
|
categories: categoriesResponse.data || [],
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading data:', error)
|
console.error('Error loading data:', error)
|
||||||
|
|
@ -45,6 +51,7 @@ export const useReports = () => {
|
||||||
setData({
|
setData({
|
||||||
templates: [],
|
templates: [],
|
||||||
generatedReports: [],
|
generatedReports: [],
|
||||||
|
categories: [],
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
|
|
@ -93,7 +100,7 @@ export const useReports = () => {
|
||||||
...prevData,
|
...prevData,
|
||||||
templates: prevData.templates.map((template) =>
|
templates: prevData.templates.map((template) =>
|
||||||
template.id === id
|
template.id === id
|
||||||
? { ...template, ...updates, lastModificationTime: new Date() }
|
? { ...template, ...updates, lastModificationTime: new Date().toISOString() }
|
||||||
: template,
|
: template,
|
||||||
),
|
),
|
||||||
}))
|
}))
|
||||||
|
|
@ -127,10 +134,10 @@ export const useReports = () => {
|
||||||
async (templateId: string, parameterValues: Record<string, string>) => {
|
async (templateId: string, parameterValues: Record<string, string>) => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
try {
|
try {
|
||||||
const reportData: ReportGeneratedDto = {
|
const reportData = {
|
||||||
templateId,
|
templateId,
|
||||||
parameters: parameterValues,
|
parameters: parameterValues,
|
||||||
} as ReportGeneratedDto
|
}
|
||||||
|
|
||||||
const response = await reportsService.generateReport(reportData)
|
const response = await reportsService.generateReport(reportData)
|
||||||
const report = response.data as ReportGeneratedDto
|
const report = response.data as ReportGeneratedDto
|
||||||
|
|
@ -182,9 +189,31 @@ export const useReports = () => {
|
||||||
[data.templates],
|
[data.templates],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const loadTemplatesByCategory = useCallback(async (categoryName?: string) => {
|
||||||
|
setIsLoading(true)
|
||||||
|
try {
|
||||||
|
const templatesResponse = await reportsService.getTemplates({
|
||||||
|
sorting: '',
|
||||||
|
skipCount: 0,
|
||||||
|
maxResultCount: 1000,
|
||||||
|
category: categoryName && categoryName !== 'Tümü' ? categoryName : undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
setData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
templates: templatesResponse.data.items || [],
|
||||||
|
}))
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading templates by category:', error)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
templates: data.templates,
|
templates: data.templates,
|
||||||
generatedReports: data.generatedReports,
|
generatedReports: data.generatedReports,
|
||||||
|
categories: data.categories,
|
||||||
isLoading,
|
isLoading,
|
||||||
setIsLoading,
|
setIsLoading,
|
||||||
createTemplate,
|
createTemplate,
|
||||||
|
|
@ -193,5 +222,6 @@ export const useReports = () => {
|
||||||
generateReport,
|
generateReport,
|
||||||
getReportById,
|
getReportById,
|
||||||
getTemplateById,
|
getTemplateById,
|
||||||
|
loadTemplatesByCategory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue