Intranet AppService içerisinde tüm istekler birleştirilecek
This commit is contained in:
parent
b5c61e9a6d
commit
e29a924e87
28 changed files with 133 additions and 141 deletions
|
|
@ -6,11 +6,12 @@ namespace Kurs.Platform.Public;
|
|||
public class EventDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string CategoryName { get; set; }
|
||||
public string TypeName { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public string Location { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Place { get; set; }
|
||||
public EventOrganizerDto Organizer { get; set; }
|
||||
public int Participants { get; set; }
|
||||
public List<string> Photos { get; set; } = new();
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
private async Task<List<EventDto>> GetUpcomingEventsAsync()
|
||||
{
|
||||
var events = await _eventRepository
|
||||
.WithDetailsAsync(e => e.Category, e => e.Type, e => e.Photos, e => e.Comments)
|
||||
.WithDetailsAsync(e => e.Category, e => e.Type, e => e.Category, e => e.Photos, e => e.Comments)
|
||||
.ContinueWith(t => t.Result.ToList().Where(e => e.isPublished).OrderByDescending(e => e.CreationTime));
|
||||
|
||||
var result = new List<EventDto>();
|
||||
|
|
@ -60,11 +60,12 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
var calendarEvent = new EventDto
|
||||
{
|
||||
Id = evt.Id.ToString(),
|
||||
Title = evt.Name,
|
||||
Name = evt.Name,
|
||||
Description = evt.Description,
|
||||
Type = evt.Type?.Name?.ToLowerInvariant() ?? "social",
|
||||
Date = evt.CreationTime,
|
||||
Location = evt.Place,
|
||||
TypeName = evt.Type?.Name,
|
||||
CategoryName = evt.Category?.Name,
|
||||
Date = evt.Date,
|
||||
Place = evt.Place,
|
||||
Organizer = new EventOrganizerDto
|
||||
{
|
||||
Id = employee.Id,
|
||||
|
|
@ -73,7 +74,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
Avatar = employee.Avatar
|
||||
},
|
||||
Participants = evt.ParticipantsCount,
|
||||
Photos = evt.Photos?.Select(p => p.Url).ToList() ?? [],
|
||||
Photos = [],
|
||||
Comments = [],
|
||||
Likes = evt.Likes,
|
||||
IsPublished = evt.isPublished
|
||||
|
|
|
|||
|
|
@ -12,9 +12,10 @@ public class Event : FullAuditedEntity<Guid>, IMultiTenant
|
|||
public Guid CategoryId { get; set; }
|
||||
public Guid TypeId { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Place { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Place { get; set; }
|
||||
public string Status { get; set; }
|
||||
|
||||
public Guid EmployeeId { get; set; }
|
||||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
|||
namespace Kurs.Platform.Migrations
|
||||
{
|
||||
[DbContext(typeof(PlatformDbContext))]
|
||||
[Migration("20251028185430_Initial")]
|
||||
[Migration("20251028200151_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -3728,6 +3728,9 @@ namespace Kurs.Platform.Migrations
|
|||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
|
@ -4343,9 +4343,10 @@ namespace Kurs.Platform.Migrations
|
|||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TypeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Date = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Place = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||
Place = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
ParticipantsCount = table.Column<int>(type: "int", nullable: false),
|
||||
|
|
@ -3725,6 +3725,9 @@ namespace Kurs.Platform.Migrations
|
|||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
|
|
|||
|
|
@ -1509,12 +1509,13 @@
|
|||
{
|
||||
"CategoryName": "Spor",
|
||||
"TypeName": "Futbol Turnuvası",
|
||||
"Date": "2025-11-15T10:00:00",
|
||||
"Name": "Yaz Futbol Turnuvası 2025",
|
||||
"Place": "Şirket Kampüsü Spor Alanı",
|
||||
"Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.",
|
||||
"Place": "Şirket Kampüsü Spor Alanı",
|
||||
"Status": "Published",
|
||||
"ParticipantsCount": 64,
|
||||
"OrganizerEmployeeCode": "EMP-001",
|
||||
"ParticipantsCount": 64,
|
||||
"IsPublished": true,
|
||||
"Likes": 120,
|
||||
"Photos": [],
|
||||
|
|
@ -1523,12 +1524,13 @@
|
|||
{
|
||||
"CategoryName": "Kültür",
|
||||
"TypeName": "Kültürel Sanat Günü",
|
||||
"Date": "2025-11-17T10:00:00",
|
||||
"Name": "Kültür Gezisi: Kapadokya",
|
||||
"Place": "Kapadokya, Nevşehir",
|
||||
"Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.",
|
||||
"Place": "Kapadokya, Nevşehir",
|
||||
"Status": "Published",
|
||||
"ParticipantsCount": 25,
|
||||
"OrganizerEmployeeCode": "EMP-002",
|
||||
"ParticipantsCount": 25,
|
||||
"IsPublished": true,
|
||||
"Likes": 45,
|
||||
"Photos": [],
|
||||
|
|
@ -1537,12 +1539,13 @@
|
|||
{
|
||||
"CategoryName": "Müzik",
|
||||
"TypeName": "Caz Akşamı",
|
||||
"Date": "2025-11-18T10:00:00",
|
||||
"Name": "Müzik Dinletisi: Jazz Akşamı",
|
||||
"Place": "Şirket Konferans Salonu",
|
||||
"Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.",
|
||||
"Place": "Şirket Konferans Salonu",
|
||||
"Status": "Published",
|
||||
"ParticipantsCount": 40,
|
||||
"OrganizerEmployeeCode": "EMP-003",
|
||||
"ParticipantsCount": 40,
|
||||
"IsPublished": true,
|
||||
"Likes": 85,
|
||||
"Photos": [],
|
||||
|
|
|
|||
|
|
@ -1538,6 +1538,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
{
|
||||
CategoryId = category.Id,
|
||||
TypeId = type.Id,
|
||||
Date = item.Date,
|
||||
Name = item.Name,
|
||||
Place = item.Place,
|
||||
Description = item.Description,
|
||||
|
|
|
|||
|
|
@ -699,9 +699,10 @@ public class EventSeedDto
|
|||
{
|
||||
public string CategoryName { get; set; }
|
||||
public string TypeName { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Place { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Place { get; set; }
|
||||
public string Status { get; set; }
|
||||
public string OrganizerEmployeeCode { get; set; }
|
||||
public int ParticipantsCount { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { EventDto } from '@/proxy/intranet/models'
|
||||
import { mockEmployees } from './mockEmployees'
|
||||
import {
|
||||
Announcement,
|
||||
CalendarEvent,
|
||||
Visitor,
|
||||
Document,
|
||||
Certificate,
|
||||
|
|
@ -822,15 +822,16 @@ export const mockSocialPosts: SocialPost[] = [
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
///////APP SERVİS YAPILANLAR//////////
|
||||
export const mockEvents: CalendarEvent[] = [
|
||||
export const mockEvents: EventDto[] = [
|
||||
{
|
||||
id: 'evt1',
|
||||
title: 'Yaz Pikniği 2025',
|
||||
name: 'Yaz Pikniği 2025',
|
||||
description:
|
||||
'Şirket çalışanları olarak doğayla iç içe harika bir gün geçirdik. Takım oyunları, barbekü ve çok eğlence!',
|
||||
type: 'social',
|
||||
categoryName: 'Spor',
|
||||
typeName: 'Futbol Turnuvası',
|
||||
date: new Date('2025-10-20'),
|
||||
location: 'Polonezköy Piknik Alanı',
|
||||
place: 'Polonezköy Piknik Alanı',
|
||||
organizer: mockEmployees[4],
|
||||
participants: 45,
|
||||
photos: [
|
||||
|
|
@ -860,11 +861,12 @@ export const mockEvents: CalendarEvent[] = [
|
|||
},
|
||||
{
|
||||
id: 'evt2',
|
||||
title: 'Hackathon 2025',
|
||||
name: 'Hackathon 2025',
|
||||
description: '24 saatlik yazılım geliştirme maratonu. İnovasyon, teknoloji ve takım çalışması!',
|
||||
type: 'training',
|
||||
categoryName: 'Spor',
|
||||
typeName: 'training',
|
||||
date: new Date('2025-20-22'),
|
||||
location: 'Ofis - Ana Salon',
|
||||
place: 'Ofis - Ana Salon',
|
||||
organizer: mockEmployees[0],
|
||||
participants: 28,
|
||||
photos: [
|
||||
|
|
@ -893,11 +895,12 @@ export const mockEvents: CalendarEvent[] = [
|
|||
},
|
||||
{
|
||||
id: 'evt3',
|
||||
title: 'Kurumsal Futbol Turnuvası',
|
||||
name: 'Kurumsal Futbol Turnuvası',
|
||||
description: 'Departmanlar arası futbol turnuvasında ter döktük, gol attık ve kazandık! 🏆',
|
||||
type: 'sport',
|
||||
categoryName: 'Spor',
|
||||
typeName: 'sport',
|
||||
date: new Date('2025-10-25'),
|
||||
location: 'Spor Kompleksi Halı Saha',
|
||||
place: 'Spor Kompleksi Halı Saha',
|
||||
organizer: mockEmployees[2],
|
||||
participants: 32,
|
||||
photos: [
|
||||
|
|
@ -920,11 +923,12 @@ export const mockEvents: CalendarEvent[] = [
|
|||
},
|
||||
{
|
||||
id: 'evt4',
|
||||
title: 'Yılbaşı Gala Gecesi 2024',
|
||||
name: 'Yılbaşı Gala Gecesi 2024',
|
||||
description: 'Harika bir yıla muhteşem bir gala ile veda ettik. Müzik, dans ve sürprizler!',
|
||||
type: 'company',
|
||||
categoryName: 'Spor',
|
||||
typeName: 'company',
|
||||
date: new Date('2024-12-28'),
|
||||
location: 'Grand Hotel - Balo Salonu',
|
||||
place: 'Grand Hotel - Balo Salonu',
|
||||
organizer: mockEmployees[3],
|
||||
participants: 68,
|
||||
photos: [
|
||||
|
|
@ -962,11 +966,12 @@ export const mockEvents: CalendarEvent[] = [
|
|||
},
|
||||
{
|
||||
id: 'evt5',
|
||||
title: 'Sanat Atölyesi - Ebru Workshop',
|
||||
name: 'Sanat Atölyesi - Ebru Workshop',
|
||||
description: 'Geleneksel Türk sanatı ebru yapımı atölyesinde harika eserler ortaya çıktı!',
|
||||
type: 'culture',
|
||||
categoryName: 'Spor',
|
||||
typeName: 'culture',
|
||||
date: new Date('2025-05-12'),
|
||||
location: 'Ofis - Yaratıcı Alan',
|
||||
place: 'Ofis - Yaratıcı Alan',
|
||||
organizer: mockEmployees[1],
|
||||
participants: 18,
|
||||
photos: [
|
||||
|
|
|
|||
31
ui/src/proxy/intranet/models.ts
Normal file
31
ui/src/proxy/intranet/models.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { HrEmployee } from '@/types/hr'
|
||||
|
||||
export interface IntranetDashboardDto {
|
||||
events: EventDto[];
|
||||
}
|
||||
|
||||
// Etkinlik
|
||||
export interface EventDto {
|
||||
id: string
|
||||
categoryName: string
|
||||
typeName: string
|
||||
date: Date
|
||||
name: string
|
||||
description: string
|
||||
place: string
|
||||
organizer: HrEmployee
|
||||
participants: number
|
||||
photos: string[]
|
||||
comments: EventCommentDto[]
|
||||
likes: number
|
||||
isPublished: boolean
|
||||
}
|
||||
|
||||
// Etkinlik Yorumu
|
||||
export interface EventCommentDto {
|
||||
id: string
|
||||
author: HrEmployee
|
||||
content: string
|
||||
creationTime: Date
|
||||
likes: number
|
||||
}
|
||||
|
|
@ -20,12 +20,4 @@ export class AiService {
|
|||
)
|
||||
}
|
||||
|
||||
export const getAi = async (skipCount = 0, maxResultCount = 1000, sorting = 'botName') => {
|
||||
const service = new AiService()
|
||||
|
||||
return await service.getList({
|
||||
sorting,
|
||||
skipCount,
|
||||
maxResultCount,
|
||||
})
|
||||
}
|
||||
export const aiService = new AiService()
|
||||
|
|
|
|||
17
ui/src/services/intranet.service.ts
Normal file
17
ui/src/services/intranet.service.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import apiService, { Config } from './api.service'
|
||||
import { IntranetDashboardDto } from '@/proxy/intranet/models'
|
||||
|
||||
export class IntranetService {
|
||||
apiName = 'Default'
|
||||
|
||||
getDashboard = (config?: Partial<Config>) =>
|
||||
apiService.fetchData<IntranetDashboardDto>(
|
||||
{
|
||||
method: 'GET',
|
||||
url: '/api/app/intranet/intranet-dashboard',
|
||||
},
|
||||
{ apiName: this.apiName, ...config },
|
||||
)
|
||||
}
|
||||
|
||||
export const intranetService = new IntranetService()
|
||||
|
|
@ -17,31 +17,6 @@ export interface Announcement {
|
|||
imageUrl?: string
|
||||
}
|
||||
|
||||
// Etkinlik
|
||||
export interface CalendarEvent {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
type: 'social' | 'training' | 'company' | 'sport' | 'culture'
|
||||
date: Date
|
||||
location: string
|
||||
organizer: HrEmployee
|
||||
participants: number
|
||||
photos: string[]
|
||||
comments: EventComment[]
|
||||
likes: number
|
||||
isPublished: boolean
|
||||
}
|
||||
|
||||
// Etkinlik Yorumu
|
||||
export interface EventComment {
|
||||
id: string
|
||||
author: HrEmployee
|
||||
content: string
|
||||
creationTime: Date
|
||||
likes: number
|
||||
}
|
||||
|
||||
// Harcama
|
||||
export interface ExpenseRequest {
|
||||
id: string
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useState, useRef, useEffect, SyntheticEvent } from 'react'
|
||||
import { FaRobot } from 'react-icons/fa';
|
||||
import { FaRobot } from 'react-icons/fa'
|
||||
import { useStoreActions, useStoreState } from '@/store'
|
||||
import { Avatar, Dropdown } from '@/components/ui'
|
||||
import LoadAiPostsFromLocalStorage from './LoadAiPostsFromLocalStorage'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { getAi } from '@/services/ai.service'
|
||||
import { aiService } from '@/services/ai.service'
|
||||
import { AiDto } from '@/proxy/ai/models'
|
||||
import { Container } from '@/components/shared'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
|
@ -60,7 +60,11 @@ const Assistant = () => {
|
|||
useEffect(() => {
|
||||
const fetchBots = async () => {
|
||||
try {
|
||||
const result = await getAi()
|
||||
const result = await aiService.getList({
|
||||
skipCount: 0,
|
||||
maxResultCount: 1000,
|
||||
sorting: 'botName',
|
||||
})
|
||||
const items =
|
||||
result?.data?.items?.map((bot: AiDto) => ({
|
||||
key: bot.id!,
|
||||
|
|
|
|||
|
|
@ -34,18 +34,13 @@ import SocialWall from './SocialWall'
|
|||
import { Announcement, Survey, SurveyAnswer } from '@/types/intranet'
|
||||
import { Container } from '@/components/shared'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { IntranetDashboardDto } from '@/proxy/intranet/models'
|
||||
import { intranetService, IntranetService } from '@/services/intranet.service'
|
||||
|
||||
dayjs.locale('tr')
|
||||
dayjs.extend(relativeTime)
|
||||
dayjs.extend(isBetween)
|
||||
|
||||
interface WidgetConfig {
|
||||
id: string
|
||||
permission: string
|
||||
component: React.ReactNode
|
||||
column: 'left' | 'center' | 'right'
|
||||
}
|
||||
|
||||
const WIDGET_ORDER_KEY = 'dashboard-widget-order'
|
||||
|
||||
const IntranetDashboard: React.FC = () => {
|
||||
|
|
@ -63,6 +58,18 @@ const IntranetDashboard: React.FC = () => {
|
|||
center: [],
|
||||
right: [],
|
||||
})
|
||||
|
||||
const [intranetDashboard, setIntranetDashboard] = useState<IntranetDashboardDto>()
|
||||
|
||||
const fetchIntranetDashboard = async () => {
|
||||
const dashboard = await intranetService.getDashboard()
|
||||
setIntranetDashboard(dashboard.data)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchIntranetDashboard()
|
||||
}, [])
|
||||
|
||||
// Drag state'leri birleştirildi
|
||||
const [dragState, setDragState] = useState<{
|
||||
draggedId: string | null
|
||||
|
|
@ -173,11 +180,6 @@ const IntranetDashboard: React.FC = () => {
|
|||
e.dataTransfer.setData('sourceColumn', column)
|
||||
}
|
||||
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
}
|
||||
|
||||
const handleDragEnterWidget = (e: React.DragEvent, column: string, index: number) => {
|
||||
// Sadece widget'ın üst kısmına yakınsa indicator göster
|
||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()
|
||||
|
|
@ -243,7 +245,7 @@ const IntranetDashboard: React.FC = () => {
|
|||
const renderWidgetComponent = (widgetId: string) => {
|
||||
switch (widgetId) {
|
||||
case 'upcoming-events':
|
||||
return <UpcomingEvents />
|
||||
return <UpcomingEvents events={intranetDashboard?.events || []} />
|
||||
case 'today-birthdays':
|
||||
return <TodayBirthdays />
|
||||
case 'recent-documents':
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
import React from 'react'
|
||||
import { FaCalendarAlt } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { mockEvents } from '../../../mocks/mockIntranet'
|
||||
|
||||
const TodayEvents: React.FC = () => {
|
||||
const todayEvents = mockEvents.filter(
|
||||
(event) => event.isPublished && dayjs(event.date).isSame(dayjs(), 'day'),
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaCalendarAlt className="w-5 h-5" />
|
||||
Bugün
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{todayEvents.length > 0 ? (
|
||||
todayEvents.map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="p-3 rounded-lg border-l-4 bg-gray-50 dark:bg-gray-700/50 border-l-blue-500"
|
||||
>
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{event.title}
|
||||
</h4>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||
{dayjs(event.date).format('DD MMMM YYYY')} - {event.location}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
{event.participants} katılımcı
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Bugün etkinlik yok
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TodayEvents
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import React from 'react'
|
||||
import { FaCalendarAlt } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { mockEvents } from '../../../mocks/mockIntranet'
|
||||
import { EventDto } from '@/proxy/intranet/models'
|
||||
|
||||
const UpcomingEvents: React.FC = () => {
|
||||
const upcomingEvents = mockEvents.filter(
|
||||
const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
|
||||
const upcomingEvents = events.filter(
|
||||
(event) =>
|
||||
event.isPublished &&
|
||||
dayjs(event.date).isAfter(dayjs()) &&
|
||||
|
|
@ -26,11 +26,9 @@ const UpcomingEvents: React.FC = () => {
|
|||
key={event.id}
|
||||
className="p-3 rounded-lg border-l-4 bg-gray-50 dark:bg-gray-700/50 border-l-green-500"
|
||||
>
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{event.title}
|
||||
</h4>
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">{event.name}</h4>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||
{dayjs(event.date).format('DD MMMM YYYY')} - {event.location}
|
||||
{dayjs(event.date).format('DD MMMM YYYY')} - {event.place}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
|
|
|
|||
Loading…
Reference in a new issue