The LARP events system allows users to discover upcoming roleplay events, register for participation, and receive notifications. Admins can create, update, and manage events.
Overview
The events system provides:
Event listing with all upcoming LARP events
Event registration for users to sign up
Registration tracking to show which events users are attending
Event notifications for registered users
Admin management for creating, updating, and deleting events
Date-based sorting for chronological event display
Event Model
Events are represented by the RoleplayEvent class:
lib/model/roleplay_event.dart
class RoleplayEvent {
final int id;
final String name;
final String description;
final String fechaInicio;
final String fechaFin;
bool isRegistered;
RoleplayEvent ({
required this .id,
required this .name,
required this .description,
required this .fechaInicio,
required this .fechaFin,
this .isRegistered = false ,
});
factory RoleplayEvent . fromJson ( Map < String , dynamic > json) {
final id = _asInt (json[ 'id' ]);
final name = _asString (json[ 'nombre' ] ?? json[ 'name' ]);
final description = _asString (json[ 'descripcion' ] ?? json[ 'description' ]);
final fechaInicio = _asString (json[ 'fecha_inicio' ] ?? json[ 'fechaInicio' ]);
final fechaFin = _asString (json[ 'fecha_fin' ] ?? json[ 'fechaFin' ]);
if (id == null ||
name == null ||
description == null ||
fechaInicio == null ||
fechaFin == null ) {
throw const FormatException ( 'Fallo al cargar evento' );
}
return RoleplayEvent (
id : id,
name : name,
description : description,
fechaInicio : fechaInicio,
fechaFin : fechaFin,
);
}
}
Event Fields
Field Type Description idintUnique numeric event ID nameStringEvent name/title descriptionStringEvent description and details fechaInicioStringStart date (ISO 8601 format) fechaFinStringEnd date (ISO 8601 format) isRegisteredboolWhether current user is registered (mutable)
Fetching Events
Retrieve all events with optional registration status:
lib/service/roleplay_event.dart
Future < List < RoleplayEvent >> fetchEventList ({ int ? userId}) async {
FirebaseBackend . ensureInitialized ();
final registeredEventIds = userId == null
? const < int > {}
: await fetchRegisteredEventIds (userId);
final events = ( await FirebaseBackend .events. orderBy ( 'id' ). get ()).docs
. map ( FirebaseBackend .normalizeSnapshotData)
. map ( RoleplayEvent .fromJson)
. toList (growable : false );
if (registeredEventIds.isEmpty) {
return events;
}
for ( final event in events) {
event.isRegistered = registeredEventIds. contains (event.id);
}
return events;
}
Fetch Process
Load user registrations if userId provided
Fetch all events from events collection
Order by ID for consistent ordering
Parse to RoleplayEvent models
Mark registration status for each event
The isRegistered flag is set based on the user’s registration data, allowing the UI to show registration state.
Event Registration
Users can register for events:
lib/service/roleplay_event.dart
Future < void > registerUserInEvent ({
required int userId,
required int eventId,
}) async {
FirebaseBackend . ensureInitialized ();
final docId = ' ${ userId } _ $ eventId ' ;
await _eventRegistrations. doc (docId). set ( < String , dynamic > {
'id' : docId,
'user_id' : userId,
'event_id' : eventId,
'created_at' : FieldValue . serverTimestamp (),
'updated_at' : FieldValue . serverTimestamp (),
}, SetOptions (merge : true ));
}
Registration Process
Create composite document ID {userId}_{eventId}
Store registration in event_registrations collection
Add timestamps for tracking
Registration Schema
{
"id" : "456_123" ,
"user_id" : 456 ,
"event_id" : 123 ,
"created_at" : "2024-01-20T10:30:00Z" ,
"updated_at" : "2024-01-20T10:30:00Z"
}
Canceling Registration
Users can cancel their event registration:
lib/service/roleplay_event.dart
Future < void > cancelUserEventRegistration ({
required int userId,
required int eventId,
}) async {
FirebaseBackend . ensureInitialized ();
final docId = ' ${ userId } _ $ eventId ' ;
final ref = _eventRegistrations. doc (docId);
final snapshot = await ref. get ();
if ( ! snapshot.exists) {
return ;
}
await ref. delete ();
}
Canceling registration is a soft delete - it simply removes the registration document. The event itself remains unchanged.
Fetching User’s Registered Events
Get all events a user is registered for:
lib/service/roleplay_event.dart
Future < List < RoleplayEvent >> fetchRegisteredEventsForUser ( int userId) async {
final events = await fetchEventList (userId : userId);
final registered = events. where ((event) => event.isRegistered). toList ();
registered. sort ((a, b) {
final aDate = DateTime . tryParse (a.fechaInicio);
final bDate = DateTime . tryParse (b.fechaInicio);
if (aDate == null && bDate == null ) return 0 ;
if (aDate == null ) return 1 ;
if (bDate == null ) return - 1 ;
return aDate. compareTo (bDate);
});
return registered;
}
Sorting Logic
Events sorted by start date (earliest first)
Invalid dates sorted to the end
Useful for displaying “My Events” in chronological order
Admin Event Management
Creating Events
lib/service/roleplay_event.dart
Future < RoleplayEvent > addEvent (
String name,
String description,
String fechaInicio,
String fechaFin,
) async {
FirebaseBackend . ensureInitialized ();
final id = await FirebaseBackend . nextNumericId ( 'events' );
final data = < String , dynamic > {
'id' : id,
'nombre' : name,
'descripcion' : description,
'fecha_inicio' : fechaInicio,
'fecha_fin' : fechaFin,
'created_at' : DateTime . now (). toUtc (). toIso8601String (),
'updated_at' : DateTime . now (). toUtc (). toIso8601String (),
};
await FirebaseBackend .events. add (data);
return RoleplayEvent . fromJson (data);
}
Event Creation Steps
Generate numeric ID using atomic counter
Create event document in events collection
Add timestamps for tracking
Return RoleplayEvent for immediate display
Updating Events
lib/service/roleplay_event.dart
Future < void > updateEvent (
int id, {
required String name,
required String description,
required String fechaInicio,
required String fechaFin,
}) async {
FirebaseBackend . ensureInitialized ();
final ref = await FirebaseBackend . findRefByNumericId ( FirebaseBackend .events, id);
await ref. set ( < String , dynamic > {
'nombre' : name,
'descripcion' : description,
'fecha_inicio' : fechaInicio,
'fecha_fin' : fechaFin,
'updated_at' : DateTime . now (). toUtc (). toIso8601String (),
}, SetOptions (merge : true ));
}
Updating an event does not affect existing registrations. Users remain registered even if event details change.
Deleting Events
lib/service/roleplay_event.dart
Future < void > deleteEvent ( int id) async {
FirebaseBackend . ensureInitialized ();
final ref = await FirebaseBackend . findRefByNumericId ( FirebaseBackend .events, id);
await ref. delete ();
final registrations = await _eventRegistrations
. where ( 'event_id' , isEqualTo : id)
. get ();
for ( final doc in registrations.docs) {
await doc.reference. delete ();
}
}
Deletion Process
Delete event document from events collection
Find all registrations for this event
Delete all registrations to maintain data consistency
Deleting an event removes all user registrations for that event. This action cannot be undone.
Registration Tracking
Fetch event IDs a user is registered for:
lib/service/roleplay_event.dart
Future < Set < int >> fetchRegisteredEventIds ( int userId) async {
FirebaseBackend . ensureInitialized ();
final snapshot =
await _eventRegistrations. where ( 'user_id' , isEqualTo : userId). get ();
return snapshot.docs
. map ((doc) => doc. data ()[ 'event_id' ])
. map (_asInt)
. whereType < int >()
. toSet ();
}
Returns a Set<int> of event IDs for efficient lookup when displaying event lists.
Firestore Collections
Events Collection
{
"id" : 1 ,
"nombre" : "Medieval Quest Weekend" ,
"descripcion" : "A three-day medieval fantasy LARP event featuring battles, quests, and intrigue." ,
"fecha_inicio" : "2024-03-15T10:00:00Z" ,
"fecha_fin" : "2024-03-17T18:00:00Z" ,
"created_at" : "2024-01-10T09:00:00Z" ,
"updated_at" : "2024-01-15T14:30:00Z"
}
Event Registrations Collection
{
"id" : "456_1" ,
"user_id" : 456 ,
"event_id" : 1 ,
"created_at" : "2024-02-01T12:00:00Z" ,
"updated_at" : "2024-02-01T12:00:00Z"
}
UI Integration
Event Display
Events are displayed using the EventCard component which shows:
Event name and description
Start and end dates
Registration status (registered/not registered)
Registration/cancel buttons
if (event.isRegistered) {
ElevatedButton (
onPressed : () async {
await cancelUserEventRegistration (
userId : currentUserId,
eventId : event.id,
);
setState (() => event.isRegistered = false );
},
child : Text ( 'Cancel Registration' ),
);
} else {
ElevatedButton (
onPressed : () async {
await registerUserInEvent (
userId : currentUserId,
eventId : event.id,
);
setState (() => event.isRegistered = true );
},
child : Text ( 'Register' ),
);
}
Event Notifications
The system supports event notifications for registered users. Notifications can be triggered:
When a user registers for an event
Before an event starts (reminder notifications)
When event details are updated
When an event is cancelled
Notification implementation details depend on your Firebase Cloud Messaging (FCM) setup.
User Roles Admin event management capabilities
Firebase Backend Event storage in Firestore
Authentication User session for registration tracking