Intranet AppService içerisinde tüm istekler birleştirilecek

This commit is contained in:
Sedat Öztürk 2025-10-28 23:12:06 +03:00
parent b5c61e9a6d
commit e29a924e87
28 changed files with 133 additions and 141 deletions

View file

@ -6,11 +6,12 @@ namespace Kurs.Platform.Public;
public class EventDto public class EventDto
{ {
public string Id { get; set; } public string Id { get; set; }
public string Title { get; set; } public string CategoryName { get; set; }
public string Description { get; set; } public string TypeName { get; set; }
public string Type { get; set; }
public DateTime Date { 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 EventOrganizerDto Organizer { get; set; }
public int Participants { get; set; } public int Participants { get; set; }
public List<string> Photos { get; set; } = new(); public List<string> Photos { get; set; } = new();

View file

@ -45,7 +45,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
private async Task<List<EventDto>> GetUpcomingEventsAsync() private async Task<List<EventDto>> GetUpcomingEventsAsync()
{ {
var events = await _eventRepository 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)); .ContinueWith(t => t.Result.ToList().Where(e => e.isPublished).OrderByDescending(e => e.CreationTime));
var result = new List<EventDto>(); var result = new List<EventDto>();
@ -60,11 +60,12 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
var calendarEvent = new EventDto var calendarEvent = new EventDto
{ {
Id = evt.Id.ToString(), Id = evt.Id.ToString(),
Title = evt.Name, Name = evt.Name,
Description = evt.Description, Description = evt.Description,
Type = evt.Type?.Name?.ToLowerInvariant() ?? "social", TypeName = evt.Type?.Name,
Date = evt.CreationTime, CategoryName = evt.Category?.Name,
Location = evt.Place, Date = evt.Date,
Place = evt.Place,
Organizer = new EventOrganizerDto Organizer = new EventOrganizerDto
{ {
Id = employee.Id, Id = employee.Id,
@ -73,7 +74,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
Avatar = employee.Avatar Avatar = employee.Avatar
}, },
Participants = evt.ParticipantsCount, Participants = evt.ParticipantsCount,
Photos = evt.Photos?.Select(p => p.Url).ToList() ?? [], Photos = [],
Comments = [], Comments = [],
Likes = evt.Likes, Likes = evt.Likes,
IsPublished = evt.isPublished IsPublished = evt.isPublished

View file

@ -12,9 +12,10 @@ public class Event : FullAuditedEntity<Guid>, IMultiTenant
public Guid CategoryId { get; set; } public Guid CategoryId { get; set; }
public Guid TypeId { get; set; } public Guid TypeId { get; set; }
public DateTime Date { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Place { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Place { get; set; }
public string Status { get; set; } public string Status { get; set; }
public Guid EmployeeId { get; set; } public Guid EmployeeId { get; set; }

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Migrations namespace Kurs.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20251028185430_Initial")] [Migration("20251028200151_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -3728,6 +3728,9 @@ namespace Kurs.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId"); .HasColumnName("CreatorId");
b.Property<DateTime>("Date")
.HasColumnType("datetime2");
b.Property<Guid?>("DeleterId") b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId"); .HasColumnName("DeleterId");

View file

@ -4343,9 +4343,10 @@ namespace Kurs.Platform.Migrations
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TypeId = 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), 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), 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), Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ParticipantsCount = table.Column<int>(type: "int", nullable: false), ParticipantsCount = table.Column<int>(type: "int", nullable: false),

View file

@ -3725,6 +3725,9 @@ namespace Kurs.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId"); .HasColumnName("CreatorId");
b.Property<DateTime>("Date")
.HasColumnType("datetime2");
b.Property<Guid?>("DeleterId") b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId"); .HasColumnName("DeleterId");

View file

@ -1509,12 +1509,13 @@
{ {
"CategoryName": "Spor", "CategoryName": "Spor",
"TypeName": "Futbol Turnuvası", "TypeName": "Futbol Turnuvası",
"Date": "2025-11-15T10:00:00",
"Name": "Yaz Futbol Turnuvası 2025", "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ı.", "Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.",
"Place": "Şirket Kampüsü Spor Alanı",
"Status": "Published", "Status": "Published",
"ParticipantsCount": 64,
"OrganizerEmployeeCode": "EMP-001", "OrganizerEmployeeCode": "EMP-001",
"ParticipantsCount": 64,
"IsPublished": true, "IsPublished": true,
"Likes": 120, "Likes": 120,
"Photos": [], "Photos": [],
@ -1523,12 +1524,13 @@
{ {
"CategoryName": "Kültür", "CategoryName": "Kültür",
"TypeName": "Kültürel Sanat Günü", "TypeName": "Kültürel Sanat Günü",
"Date": "2025-11-17T10:00:00",
"Name": "Kültür Gezisi: Kapadokya", "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.", "Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.",
"Place": "Kapadokya, Nevşehir",
"Status": "Published", "Status": "Published",
"ParticipantsCount": 25,
"OrganizerEmployeeCode": "EMP-002", "OrganizerEmployeeCode": "EMP-002",
"ParticipantsCount": 25,
"IsPublished": true, "IsPublished": true,
"Likes": 45, "Likes": 45,
"Photos": [], "Photos": [],
@ -1537,12 +1539,13 @@
{ {
"CategoryName": "Müzik", "CategoryName": "Müzik",
"TypeName": "Caz Akşamı", "TypeName": "Caz Akşamı",
"Date": "2025-11-18T10:00:00",
"Name": "Müzik Dinletisi: Jazz Akşamı", "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.", "Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.",
"Place": "Şirket Konferans Salonu",
"Status": "Published", "Status": "Published",
"ParticipantsCount": 40,
"OrganizerEmployeeCode": "EMP-003", "OrganizerEmployeeCode": "EMP-003",
"ParticipantsCount": 40,
"IsPublished": true, "IsPublished": true,
"Likes": 85, "Likes": 85,
"Photos": [], "Photos": [],

View file

@ -1538,6 +1538,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
{ {
CategoryId = category.Id, CategoryId = category.Id,
TypeId = type.Id, TypeId = type.Id,
Date = item.Date,
Name = item.Name, Name = item.Name,
Place = item.Place, Place = item.Place,
Description = item.Description, Description = item.Description,

View file

@ -699,9 +699,10 @@ public class EventSeedDto
{ {
public string CategoryName { get; set; } public string CategoryName { get; set; }
public string TypeName { get; set; } public string TypeName { get; set; }
public DateTime Date { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Place { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Place { get; set; }
public string Status { get; set; } public string Status { get; set; }
public string OrganizerEmployeeCode { get; set; } public string OrganizerEmployeeCode { get; set; }
public int ParticipantsCount { get; set; } public int ParticipantsCount { get; set; }

View file

@ -1,7 +1,7 @@
import { EventDto } from '@/proxy/intranet/models'
import { mockEmployees } from './mockEmployees' import { mockEmployees } from './mockEmployees'
import { import {
Announcement, Announcement,
CalendarEvent,
Visitor, Visitor,
Document, Document,
Certificate, Certificate,
@ -822,15 +822,16 @@ export const mockSocialPosts: SocialPost[] = [
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
///////APP SERVİS YAPILANLAR////////// ///////APP SERVİS YAPILANLAR//////////
export const mockEvents: CalendarEvent[] = [ export const mockEvents: EventDto[] = [
{ {
id: 'evt1', id: 'evt1',
title: 'Yaz Pikniği 2025', name: 'Yaz Pikniği 2025',
description: description:
'Şirket çalışanları olarak doğayla iç içe harika bir gün geçirdik. Takım oyunları, barbekü ve çok eğlence!', 'Ş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'), date: new Date('2025-10-20'),
location: 'Polonezköy Piknik Alanı', place: 'Polonezköy Piknik Alanı',
organizer: mockEmployees[4], organizer: mockEmployees[4],
participants: 45, participants: 45,
photos: [ photos: [
@ -860,11 +861,12 @@ export const mockEvents: CalendarEvent[] = [
}, },
{ {
id: 'evt2', id: 'evt2',
title: 'Hackathon 2025', name: 'Hackathon 2025',
description: '24 saatlik yazılım geliştirme maratonu. İnovasyon, teknoloji ve takım çalışması!', 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'), date: new Date('2025-20-22'),
location: 'Ofis - Ana Salon', place: 'Ofis - Ana Salon',
organizer: mockEmployees[0], organizer: mockEmployees[0],
participants: 28, participants: 28,
photos: [ photos: [
@ -893,11 +895,12 @@ export const mockEvents: CalendarEvent[] = [
}, },
{ {
id: 'evt3', 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! 🏆', 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'), date: new Date('2025-10-25'),
location: 'Spor Kompleksi Halı Saha', place: 'Spor Kompleksi Halı Saha',
organizer: mockEmployees[2], organizer: mockEmployees[2],
participants: 32, participants: 32,
photos: [ photos: [
@ -920,11 +923,12 @@ export const mockEvents: CalendarEvent[] = [
}, },
{ {
id: 'evt4', 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!', 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'), date: new Date('2024-12-28'),
location: 'Grand Hotel - Balo Salonu', place: 'Grand Hotel - Balo Salonu',
organizer: mockEmployees[3], organizer: mockEmployees[3],
participants: 68, participants: 68,
photos: [ photos: [
@ -962,11 +966,12 @@ export const mockEvents: CalendarEvent[] = [
}, },
{ {
id: 'evt5', 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ı!', 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'), date: new Date('2025-05-12'),
location: 'Ofis - Yaratıcı Alan', place: 'Ofis - Yaratıcı Alan',
organizer: mockEmployees[1], organizer: mockEmployees[1],
participants: 18, participants: 18,
photos: [ photos: [

View 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
}

View file

@ -20,12 +20,4 @@ export class AiService {
) )
} }
export const getAi = async (skipCount = 0, maxResultCount = 1000, sorting = 'botName') => { export const aiService = new AiService()
const service = new AiService()
return await service.getList({
sorting,
skipCount,
maxResultCount,
})
}

View 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()

View file

@ -17,31 +17,6 @@ export interface Announcement {
imageUrl?: string 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 // Harcama
export interface ExpenseRequest { export interface ExpenseRequest {
id: string id: string

View file

@ -1,10 +1,10 @@
import React, { useState, useRef, useEffect, SyntheticEvent } from 'react' 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 { useStoreActions, useStoreState } from '@/store'
import { Avatar, Dropdown } from '@/components/ui' import { Avatar, Dropdown } from '@/components/ui'
import LoadAiPostsFromLocalStorage from './LoadAiPostsFromLocalStorage' import LoadAiPostsFromLocalStorage from './LoadAiPostsFromLocalStorage'
import { useLocalization } from '@/utils/hooks/useLocalization' 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 { AiDto } from '@/proxy/ai/models'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
@ -60,7 +60,11 @@ const Assistant = () => {
useEffect(() => { useEffect(() => {
const fetchBots = async () => { const fetchBots = async () => {
try { try {
const result = await getAi() const result = await aiService.getList({
skipCount: 0,
maxResultCount: 1000,
sorting: 'botName',
})
const items = const items =
result?.data?.items?.map((bot: AiDto) => ({ result?.data?.items?.map((bot: AiDto) => ({
key: bot.id!, key: bot.id!,

View file

@ -34,18 +34,13 @@ import SocialWall from './SocialWall'
import { Announcement, Survey, SurveyAnswer } from '@/types/intranet' import { Announcement, Survey, SurveyAnswer } from '@/types/intranet'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
import { usePermission } from '@/utils/hooks/usePermission' import { usePermission } from '@/utils/hooks/usePermission'
import { IntranetDashboardDto } from '@/proxy/intranet/models'
import { intranetService, IntranetService } from '@/services/intranet.service'
dayjs.locale('tr') dayjs.locale('tr')
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
dayjs.extend(isBetween) dayjs.extend(isBetween)
interface WidgetConfig {
id: string
permission: string
component: React.ReactNode
column: 'left' | 'center' | 'right'
}
const WIDGET_ORDER_KEY = 'dashboard-widget-order' const WIDGET_ORDER_KEY = 'dashboard-widget-order'
const IntranetDashboard: React.FC = () => { const IntranetDashboard: React.FC = () => {
@ -63,6 +58,18 @@ const IntranetDashboard: React.FC = () => {
center: [], center: [],
right: [], right: [],
}) })
const [intranetDashboard, setIntranetDashboard] = useState<IntranetDashboardDto>()
const fetchIntranetDashboard = async () => {
const dashboard = await intranetService.getDashboard()
setIntranetDashboard(dashboard.data)
}
useEffect(() => {
fetchIntranetDashboard()
}, [])
// Drag state'leri birleştirildi // Drag state'leri birleştirildi
const [dragState, setDragState] = useState<{ const [dragState, setDragState] = useState<{
draggedId: string | null draggedId: string | null
@ -173,11 +180,6 @@ const IntranetDashboard: React.FC = () => {
e.dataTransfer.setData('sourceColumn', column) 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) => { const handleDragEnterWidget = (e: React.DragEvent, column: string, index: number) => {
// Sadece widget'ın üst kısmına yakınsa indicator göster // Sadece widget'ın üst kısmına yakınsa indicator göster
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect() const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()
@ -243,7 +245,7 @@ const IntranetDashboard: React.FC = () => {
const renderWidgetComponent = (widgetId: string) => { const renderWidgetComponent = (widgetId: string) => {
switch (widgetId) { switch (widgetId) {
case 'upcoming-events': case 'upcoming-events':
return <UpcomingEvents /> return <UpcomingEvents events={intranetDashboard?.events || []} />
case 'today-birthdays': case 'today-birthdays':
return <TodayBirthdays /> return <TodayBirthdays />
case 'recent-documents': case 'recent-documents':

View file

@ -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

View file

@ -1,10 +1,10 @@
import React from 'react' import React from 'react'
import { FaCalendarAlt } from 'react-icons/fa' import { FaCalendarAlt } from 'react-icons/fa'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockEvents } from '../../../mocks/mockIntranet' import { EventDto } from '@/proxy/intranet/models'
const UpcomingEvents: React.FC = () => { const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
const upcomingEvents = mockEvents.filter( const upcomingEvents = events.filter(
(event) => (event) =>
event.isPublished && event.isPublished &&
dayjs(event.date).isAfter(dayjs()) && dayjs(event.date).isAfter(dayjs()) &&
@ -26,11 +26,9 @@ const UpcomingEvents: React.FC = () => {
key={event.id} key={event.id}
className="p-3 rounded-lg border-l-4 bg-gray-50 dark:bg-gray-700/50 border-l-green-500" 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"> <h4 className="text-sm font-medium text-gray-900 dark:text-white">{event.name}</h4>
{event.title}
</h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1"> <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> </p>
</div> </div>
)) ))