Skip to main content

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

authSlice.js:4-8
const initialState = {
    isAuthenticated: false,
    isInitialized: false,
    user: null,
};
isAuthenticated
boolean
default:"false"
Whether the user is currently authenticated
isInitialized
boolean
default:"false"
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.
authSlice.js:14-33
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;
}
payload.isAuthenticated
boolean
required
Authentication status
payload.user
object | null
required
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

StaffSlice.js:5-9
const initialState = {
  staff: [],
  StaffSearch: '',
  error: ''
};
staff
array
default:"[]"
Array of staff user objects
Current search query for filtering staff
error
string
default:"''"
Error message if staff fetch fails

Actions

getStaff

Stores fetched staff users in state.
StaffSlice.js:20-22
getStaff: (state, action) => {
  state.staff = action.payload;
}

SearchStaff

Updates the staff search query.
StaffSlice.js:23-25
SearchStaff: (state, action) => {
  state.StaffSearch = action.payload;
}

hasError

Stores error information.
StaffSlice.js:16-18
hasError(state, action) {
  state.error = action.payload;
}

Async Thunks

fetchStaffUsers

Fetches all staff users from Firestore with timestamp conversion.
StaffSlice.js:34-66
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

ClientsSlice.js:5-9
const initialState = {
  Clients: [],
  ClientsSearch: '',
  error: ''
};
Clients
array
default:"[]"
Array of client user objects
Current search query for filtering clients
error
string
default:"''"
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

EventsSlice.js:5-11
const initialState = {
  Events: [],
  ActiveEvents: [],
  ClientEvents: [],
  EventsSearch: '',
  error: ''
};
Events
array
default:"[]"
All events in the system
ActiveEvents
array
default:"[]"
Events with status “Activo”
ClientEvents
array
default:"[]"
Events filtered by client ID
Search query for filtering events
error
string
default:"''"
Error message if events fetch fails

Actions

getEvents

Stores all fetched events.
EventsSlice.js:22-24
getEvents: (state, action) => {
  state.Events = action.payload;
}

getActiveEvents

Stores active events only.
EventsSlice.js:25-27
getActiveEvents: (state, action) => {
  state.ActiveEvents = action.payload;
}

getClientEvents

Stores events for a specific client.
EventsSlice.js:28-30
getClientEvents: (state, action) => {
  state.ClientEvents = action.payload;
}

Async Thunks

fetchEvents(id)

Fetches all events, optionally filtered by venue ID.
id
string
Optional venue ID to filter events
EventsSlice.js:45-81
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.
id
string
required
Client ID to filter events

Tickets Slice

Manages event ticket inventory and search.

State Shape

TicketsSlice.js:5-9
const initialState = {
  Ticket: [],
  TicketSearch: '',
  error: ''
};
Ticket
array
default:"[]"
Array of ticket objects for the current event
Search query for filtering tickets
error
string
default:"''"
Error message if ticket fetch fails

Async Thunks

fetchTicket(id)

Fetches tickets for a specific event using the API.
TicketsSlice.js:34-49
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));
  }
};
id
string
required
Event ID to fetch tickets for

Transactions Slice

Manages transaction data for order processing.

State Shape

transactionsSlice.js:5-9
const initialState = {
    Transactions: [],
    TransactionsSearch: '',
    error: ''
};
Transactions
array
default:"[]"
Array of transaction objects
Search query for filtering transactions
error
string
default:"''"
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));
    }
};
id
string
required
Client ID to fetch transactions for

Offices Slice

Manages box office data and selection state.

State Shape

OfficesSlice.js:5-11
const initialState = {
  Offices: [],
  SelectedOffice: null,
  ActiveOffices: [],
  OfficesSearch: '',
  error: ''
};
Offices
array
default:"[]"
All office locations
SelectedOffice
object | null
default:"null"
Currently selected office for operations
ActiveOffices
array
default:"[]"
Offices with active status
Search query for filtering offices
error
string
default:"''"
Error message if offices fetch fails

Actions

setSelectedOffice

Sets the currently active office for operations.
OfficesSlice.js:25-27
setSelectedOffice: (state, action) => {
  state.SelectedOffice = action.payload;
}
payload
object | null
required
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

ordersSlice.js:5-11
const initialState = {
    Orders: [],
    OrdersEvent: [],
    OrdersOffice: [],
    OrdersSearch: '',
    error: ''
};
Orders
array
default:"[]"
All orders for a client
OrdersEvent
array
default:"[]"
Orders filtered by event ID
OrdersOffice
array
default:"[]"
Orders filtered by office ID
Search query for filtering orders
error
string
default:"''"
Error message if orders fetch fails

Async Thunks

fetchOrders(id)

Fetches all orders for a client with transaction timestamp conversion.
ordersSlice.js:45-81
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.
id
string
required
Event ID to fetch orders for

fetchOrdersOffice(id)

Fetches orders for a specific office.
id
string
required
Office ID to fetch orders for

Contracts Slice

Manages contract documents and agreements.

State Shape

ContractsSlice.js:5-9
const initialState = {
  Contracts: [],
  ContractsSearch: '',
  error: ''
};
Contracts
array
default:"[]"
Array of contract objects
Search query for filtering contracts
error
string
default:"''"
Error message if contracts fetch fails

Async Thunks

fetchContracts(id)

Fetches contracts for a specific user.
ContractsSlice.js:34-65
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));
  }
};
id
string
required
User ID to fetch contracts for

Payouts Slice

Manages payout method configurations.

State Shape

PayoutsSlice.js:6-11
const initialState = {
  Payouts: [],
  ActivePayouts: [],
  PayoutsSearch: '',
  error: ''
};
Payouts
array
default:"[]"
All payout methods
ActivePayouts
array
default:"[]"
Payout methods with active status
Search query for filtering payouts
error
string
default:"''"
Error message if payouts fetch fails

Async Thunks

fetchPayouts(id)

Fetches all payout methods for a user.
PayoutsSlice.js:41-64
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));
  }
};
id
string
required
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>
  );
}

Build docs developers (and LLMs) love