Overview
TMT uses Redux Toolkit slices to organize state management into modular, domain-specific units. Each slice contains the state shape, reducers, and actions for a specific feature area.
Authentication Slice
Manages user authentication state and session information.
State Shape
const initialState = {
isAuthenticated: false,
isInitialized: false,
user: null,
};
Whether the user is currently authenticated
Whether the authentication system has been initialized
user
object | null
default:"null"
Current user object with profile information and timestamps
Actions
authStateChanged
Updates authentication state when user signs in/out.
authStateChanged(state, action) {
const { isAuthenticated, user } = action.payload;
if(user !== null){
const convertTimestamp = (timestamp) => {
if (timestamp && timestamp.seconds) {
const date = new Date(timestamp.seconds * 1000 + timestamp.nanoseconds / 1000000);
return moment(date).format('DD/MM/YYYY - hh:mm:ss a');
}
return null;
};
user.date.last_update = convertTimestamp(user.date?.last_update)
user.date.last_access = convertTimestamp(user.date?.last_access)
}
state.isAuthenticated = isAuthenticated;
state.isInitialized = true;
state.user = user;
}
User object with profile data, automatically converts Firebase timestamps
Usage Example
import { useDispatch, useSelector } from 'react-redux';
import { authStateChanged } from './store/apps/auth/authSlice';
function AuthProvider({ children }) {
const dispatch = useDispatch();
const { isAuthenticated, user } = useSelector((state) => state.auth);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (firebaseUser) => {
dispatch(authStateChanged({
isAuthenticated: !!firebaseUser,
user: firebaseUser,
}));
});
return unsubscribe;
}, []);
return children;
}
Staff Slice
Manages staff user data and search functionality.
State Shape
const initialState = {
staff: [],
StaffSearch: '',
error: ''
};
Array of staff user objects
Current search query for filtering staff
Error message if staff fetch fails
Actions
getStaff
Stores fetched staff users in state.
getStaff: (state, action) => {
state.staff = action.payload;
}
SearchStaff
Updates the staff search query.
SearchStaff: (state, action) => {
state.StaffSearch = action.payload;
}
hasError
Stores error information.
hasError(state, action) {
state.error = action.payload;
}
Async Thunks
fetchStaffUsers
Fetches all staff users from Firestore with timestamp conversion.
export const fetchStaffUsers = () => async (dispatch) => {
try {
const querySnapshot = await Firestore.collection('u_staff').get();
const staffArray = querySnapshot.docs.map((doc) => {
const data = doc.data();
const convertTimestamp = (timestamp) => {
if (timestamp && timestamp.seconds) {
const date = new Date(timestamp.seconds * 1000 + timestamp.nanoseconds / 1000000);
return moment(date).format('DD/MM/YYYY hh:mm:ss a');
}
return null;
};
const date = {
last_access: convertTimestamp(data.date?.last_access),
last_update: convertTimestamp(data.date?.last_update),
};
return {
id: doc.id,
...data,
date,
};
});
dispatch(getStaff(staffArray));
} catch (error) {
dispatch(hasError(error));
}
};
Clients Slice
Manages client user data with similar structure to Staff slice.
State Shape
const initialState = {
Clients: [],
ClientsSearch: '',
error: ''
};
Array of client user objects
Current search query for filtering clients
Error message if clients fetch fails
Actions & Thunks
- getClients - Stores fetched clients
- SearchClients - Updates search query
- hasError - Stores error information
- fetchClientsUsers() - Async thunk to fetch all clients from
u_clients collection
Events Slice
Manages event data with support for multiple event collections.
State Shape
const initialState = {
Events: [],
ActiveEvents: [],
ClientEvents: [],
EventsSearch: '',
error: ''
};
Events with status “Activo”
Events filtered by client ID
Search query for filtering events
Error message if events fetch fails
Actions
getEvents
Stores all fetched events.
getEvents: (state, action) => {
state.Events = action.payload;
}
getActiveEvents
Stores active events only.
getActiveEvents: (state, action) => {
state.ActiveEvents = action.payload;
}
getClientEvents
Stores events for a specific client.
getClientEvents: (state, action) => {
state.ClientEvents = action.payload;
}
Async Thunks
fetchEvents(id)
Fetches all events, optionally filtered by venue ID.
Optional venue ID to filter events
export const fetchEvents = (id) => async (dispatch) => {
try {
const querySnapshot = id
? await Firestore.collection('events').where("venue_id", "==", id).get()
: await Firestore.collection('events').get();
const EventsArray = querySnapshot.docs.map((doc) => {
const data = doc.data();
// Timestamp conversion logic...
return {
id: doc.id,
...data,
date,
date_end,
date_start
};
});
dispatch(getEvents(EventsArray));
} catch (error) {
dispatch(hasError(error));
}
};
fetchActiveEvents(id)
Fetches only active events, optionally filtered by client ID.
fetchClientEvents(id)
Fetches all events for a specific client.
Client ID to filter events
Tickets Slice
Manages event ticket inventory and search.
State Shape
const initialState = {
Ticket: [],
TicketSearch: '',
error: ''
};
Array of ticket objects for the current event
Search query for filtering tickets
Error message if ticket fetch fails
Async Thunks
fetchTicket(id)
Fetches tickets for a specific event using the API.
export const fetchTicket = (id) => async (dispatch) => {
try {
const res = await tickets_list_event({ event_id: id });
const TicketArray = res.data.response.map((doc) => {
return {
...doc,
};
});
dispatch(getTicket(TicketArray));
} catch (error) {
dispatch(hasError(error));
}
};
Event ID to fetch tickets for
Transactions Slice
Manages transaction data for order processing.
State Shape
const initialState = {
Transactions: [],
TransactionsSearch: '',
error: ''
};
Array of transaction objects
Search query for filtering transactions
Error message if transactions fetch fails
Async Thunks
fetchTransactions(id)
Fetches all transactions for a specific client.
transactionsSlice.js:35-66
export const fetchTransactions = (id) => async (dispatch) => {
try {
const querySnapshot = await Firestore.collection('orders_transactions')
.where('client_id', '==', id).get();
const TransactionsArray = querySnapshot.docs.map((doc) => {
const data = doc.data();
return {
id: doc.id,
...data,
};
});
dispatch(getTransactions(TransactionsArray));
} catch (error) {
dispatch(hasError(error));
}
};
Client ID to fetch transactions for
Offices Slice
Manages box office data and selection state.
State Shape
const initialState = {
Offices: [],
SelectedOffice: null,
ActiveOffices: [],
OfficesSearch: '',
error: ''
};
SelectedOffice
object | null
default:"null"
Currently selected office for operations
Offices with active status
Search query for filtering offices
Error message if offices fetch fails
Actions
setSelectedOffice
Sets the currently active office for operations.
setSelectedOffice: (state, action) => {
state.SelectedOffice = action.payload;
}
Office object to set as selected, or null to clear selection
Async Thunks
fetchOffices(id)
Fetches offices for a specific client.
fetchActiveOffices()
Fetches all offices with active status.
Orders Slice
Manages order data with support for multiple filtering contexts.
State Shape
const initialState = {
Orders: [],
OrdersEvent: [],
OrdersOffice: [],
OrdersSearch: '',
error: ''
};
Orders filtered by event ID
Orders filtered by office ID
Search query for filtering orders
Error message if orders fetch fails
Async Thunks
fetchOrders(id)
Fetches all orders for a client with transaction timestamp conversion.
export const fetchOrders = (id) => async (dispatch) => {
try {
const querySnapshot = await Firestore.collection('orders')
.where('client_id', '==', id).get();
const ordersArray = querySnapshot.docs.map((doc) => {
const data = doc.data();
// Convert timestamps
const convertTimestamp = (timestamp) => {
if (timestamp && timestamp.seconds) {
const date = new Date(timestamp.seconds * 1000 + timestamp.nanoseconds / 1000000);
return moment(date).format('DD/MM/YYYY - hh:mm:ss a');
}
return null;
};
const date = {
created: convertTimestamp(data.date?.created),
updated: convertTimestamp(data.date?.updated),
};
data.transactions.map((transaction, i) => {
transaction.date = convertTimestamp(transaction.date)
data.transactions[i] = transaction;
})
return {
id: doc.id,
...data,
date,
};
});
dispatch(getOrders(ordersArray));
} catch (error) {
dispatch(hasError(error));
}
};
fetchOrdersEvents(id)
Fetches orders for a specific event.
Event ID to fetch orders for
fetchOrdersOffice(id)
Fetches orders for a specific office.
Office ID to fetch orders for
Contracts Slice
Manages contract documents and agreements.
State Shape
const initialState = {
Contracts: [],
ContractsSearch: '',
error: ''
};
Array of contract objects
Search query for filtering contracts
Error message if contracts fetch fails
Async Thunks
fetchContracts(id)
Fetches contracts for a specific user.
export const fetchContracts = (id) => async (dispatch) => {
try {
const querySnapshot = await Firestore.collection('contracts')
.where('user_id', '==', id).get();
const ContractsArray = querySnapshot.docs.map((doc) => {
const data = doc.data();
// Timestamp conversion...
return {
id: doc.id,
...data,
date,
};
});
dispatch(getContracts(ContractsArray));
} catch (error) {
dispatch(hasError(error));
}
};
User ID to fetch contracts for
Payouts Slice
Manages payout method configurations.
State Shape
const initialState = {
Payouts: [],
ActivePayouts: [],
PayoutsSearch: '',
error: ''
};
Payout methods with active status
Search query for filtering payouts
Error message if payouts fetch fails
Async Thunks
fetchPayouts(id)
Fetches all payout methods for a user.
export const fetchPayouts = (id) => async (dispatch) => {
try {
const querySnapshot = await Firestore.collection('payout_methods')
.doc(id).collection('methods').get();
const PayoutsArray = querySnapshot.docs.map((doc) => {
const data = doc.data();
const date = {
created: convertTimestamp(data.date?.created),
updated: convertTimestamp(data.date?.updated),
};
return {
id: doc.id,
...data,
date,
};
});
dispatch(getPayouts(PayoutsArray));
} catch (error) {
dispatch(hasError(error));
}
};
User ID to fetch payout methods for
fetchActivePayouts(id)
Fetches only active payout methods for a user.
Common Patterns
All slices follow these consistent patterns:
Timestamp Conversion
Firebase timestamps are automatically converted to readable date strings:
const convertTimestamp = (timestamp) => {
if (timestamp && timestamp.seconds) {
const date = new Date(timestamp.seconds * 1000 + timestamp.nanoseconds / 1000000);
return moment(date).format('DD/MM/YYYY - hh:mm:ss a');
}
return null;
};
Error Handling
All async thunks include error handling:
try {
// Fetch and process data
dispatch(getDataAction(data));
} catch (error) {
dispatch(hasError(error));
}
Search Functionality
Most slices include a search state for client-side filtering:
SearchItems: (state, action) => {
state.ItemsSearch = action.payload;
}
Usage Examples
Fetching and Displaying Data
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchEvents } from './store/apps/events/EventsSlice';
function EventsList() {
const dispatch = useDispatch();
const { Events, EventsSearch, error } = useSelector((state) => state.events);
useEffect(() => {
dispatch(fetchEvents());
}, [dispatch]);
const filteredEvents = Events.filter(event =>
event.name.toLowerCase().includes(EventsSearch.toLowerCase())
);
if (error) return <div>Error: {error}</div>;
return (
<div>
{filteredEvents.map(event => (
<EventCard key={event.id} event={event} />
))}
</div>
);
}
Managing Office Selection
import { useDispatch, useSelector } from 'react-redux';
import { setSelectedOffice } from './store/apps/offices/OfficesSlice';
function OfficeSelector() {
const dispatch = useDispatch();
const { Offices, SelectedOffice } = useSelector((state) => state.offices);
const handleOfficeChange = (office) => {
dispatch(setSelectedOffice(office));
};
return (
<select
value={SelectedOffice?.id || ''}
onChange={(e) => {
const office = Offices.find(o => o.id === e.target.value);
handleOfficeChange(office);
}}
>
<option value="">Select Office</option>
{Offices.map(office => (
<option key={office.id} value={office.id}>
{office.name}
</option>
))}
</select>
);
}
Searching and Filtering
import { useDispatch, useSelector } from 'react-redux';
import { SearchClients } from './store/apps/Users/ClientsSlice';
function ClientSearch() {
const dispatch = useDispatch();
const { Clients, ClientsSearch } = useSelector((state) => state.clients);
const handleSearch = (query) => {
dispatch(SearchClients(query));
};
const filteredClients = Clients.filter(client =>
client.name.toLowerCase().includes(ClientsSearch.toLowerCase()) ||
client.email.toLowerCase().includes(ClientsSearch.toLowerCase())
);
return (
<div>
<input
type="text"
value={ClientsSearch}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search clients..."
/>
<ClientList clients={filteredClients} />
</div>
);
}