mirror of
https://github.com/johndoe6345789/workforce-pay-bill-p.git
synced 2026-04-24 13:24:57 +00:00
301 lines
8.5 KiB
Markdown
301 lines
8.5 KiB
Markdown
# Redux Integration Guide
|
|
|
|
This application uses Redux Toolkit for centralized state management across the entire platform.
|
|
|
|
## Architecture Overview
|
|
|
|
The Redux store is configured in `/src/store/store.ts` and provides the following slices:
|
|
|
|
### State Slices
|
|
|
|
#### 1. Auth Slice (`/src/store/slices/authSlice.ts`)
|
|
Manages authentication state and user information.
|
|
|
|
**State:**
|
|
- `user`: Current authenticated user object
|
|
- `isAuthenticated`: Boolean flag for auth status
|
|
- `currentEntity`: Selected organizational entity
|
|
|
|
**Actions:**
|
|
- `login(user)`: Authenticates user and stores user data
|
|
- `logout()`: Clears user session
|
|
- `setCurrentEntity(entity)`: Switches between organizational entities
|
|
|
|
#### 2. UI Slice (`/src/store/slices/uiSlice.ts`)
|
|
Manages global UI state.
|
|
|
|
**State:**
|
|
- `currentView`: Active view/page in the application
|
|
- `searchQuery`: Global search query string
|
|
- `sidebarCollapsed`: Sidebar visibility state
|
|
|
|
**Actions:**
|
|
- `setCurrentView(view)`: Navigate to different views
|
|
- `setSearchQuery(query)`: Update search query
|
|
- `toggleSidebar()`: Toggle sidebar collapsed state
|
|
|
|
#### 3. Timesheets Slice (`/src/store/slices/timesheetsSlice.ts`)
|
|
Manages timesheet data.
|
|
|
|
**State:**
|
|
- `timesheets`: Array of timesheet objects
|
|
- `loading`: Loading state for async operations
|
|
|
|
**Actions:**
|
|
- `setTimesheets(timesheets)`: Replace all timesheets
|
|
- `addTimesheet(timesheet)`: Add new timesheet
|
|
- `updateTimesheet(timesheet)`: Update existing timesheet
|
|
- `deleteTimesheet(id)`: Remove timesheet by ID
|
|
- `setLoading(boolean)`: Set loading state
|
|
|
|
#### 4. Invoices Slice (`/src/store/slices/invoicesSlice.ts`)
|
|
Manages invoice data.
|
|
|
|
**State:**
|
|
- `invoices`: Array of invoice objects
|
|
- `loading`: Loading state for async operations
|
|
|
|
**Actions:**
|
|
- `setInvoices(invoices)`: Replace all invoices
|
|
- `addInvoice(invoice)`: Add new invoice
|
|
- `updateInvoice(invoice)`: Update existing invoice
|
|
- `deleteInvoice(id)`: Remove invoice by ID
|
|
- `setLoading(boolean)`: Set loading state
|
|
|
|
#### 5. Payroll Slice (`/src/store/slices/payrollSlice.ts`)
|
|
Manages payroll run data.
|
|
|
|
**State:**
|
|
- `payrollRuns`: Array of payroll run objects
|
|
- `loading`: Loading state for async operations
|
|
|
|
**Actions:**
|
|
- `setPayrollRuns(runs)`: Replace all payroll runs
|
|
- `addPayrollRun(run)`: Add new payroll run
|
|
- `updatePayrollRun(run)`: Update existing payroll run
|
|
- `setLoading(boolean)`: Set loading state
|
|
|
|
#### 6. Compliance Slice (`/src/store/slices/complianceSlice.ts`)
|
|
Manages compliance document data.
|
|
|
|
**State:**
|
|
- `documents`: Array of compliance document objects
|
|
- `loading`: Loading state for async operations
|
|
|
|
**Actions:**
|
|
- `setComplianceDocs(docs)`: Replace all compliance documents
|
|
- `addComplianceDoc(doc)`: Add new compliance document
|
|
- `updateComplianceDoc(doc)`: Update existing compliance document
|
|
- `deleteComplianceDoc(id)`: Remove compliance document by ID
|
|
- `setLoading(boolean)`: Set loading state
|
|
|
|
#### 7. Expenses Slice (`/src/store/slices/expensesSlice.ts`)
|
|
Manages expense data.
|
|
|
|
**State:**
|
|
- `expenses`: Array of expense objects
|
|
- `loading`: Loading state for async operations
|
|
|
|
**Actions:**
|
|
- `setExpenses(expenses)`: Replace all expenses
|
|
- `addExpense(expense)`: Add new expense
|
|
- `updateExpense(expense)`: Update existing expense
|
|
- `deleteExpense(id)`: Remove expense by ID
|
|
- `setLoading(boolean)`: Set loading state
|
|
|
|
#### 8. Notifications Slice (`/src/store/slices/notificationsSlice.ts`)
|
|
Manages system notifications.
|
|
|
|
**State:**
|
|
- `notifications`: Array of notification objects
|
|
- `unreadCount`: Number of unread notifications
|
|
|
|
**Actions:**
|
|
- `setNotifications(notifications)`: Replace all notifications
|
|
- `addNotification(notification)`: Add new notification
|
|
- `markAsRead(id)`: Mark notification as read
|
|
- `markAllAsRead()`: Mark all notifications as read
|
|
- `deleteNotification(id)`: Remove notification by ID
|
|
|
|
## Using Redux in Components
|
|
|
|
### 1. Import the typed hooks
|
|
|
|
```typescript
|
|
import { useAppSelector, useAppDispatch } from '@/store/hooks'
|
|
```
|
|
|
|
### 2. Access state with useAppSelector
|
|
|
|
```typescript
|
|
const user = useAppSelector(state => state.auth.user)
|
|
const isAuthenticated = useAppSelector(state => state.auth.isAuthenticated)
|
|
const timesheets = useAppSelector(state => state.timesheets.timesheets)
|
|
```
|
|
|
|
### 3. Dispatch actions with useAppDispatch
|
|
|
|
```typescript
|
|
import { login, logout } from '@/store/slices/authSlice'
|
|
import { setCurrentView } from '@/store/slices/uiSlice'
|
|
|
|
const dispatch = useAppDispatch()
|
|
|
|
// Dispatch actions
|
|
dispatch(login({ id: '1', email: 'user@example.com', name: 'User', role: 'Admin' }))
|
|
dispatch(setCurrentView('dashboard'))
|
|
dispatch(logout())
|
|
```
|
|
|
|
## Custom Hooks with Redux
|
|
|
|
We've created several custom hooks that wrap Redux logic for cleaner component code:
|
|
|
|
### useAuth Hook (`/src/hooks/use-auth.ts`)
|
|
|
|
```typescript
|
|
import { useAuth } from '@/hooks/use-auth'
|
|
|
|
function MyComponent() {
|
|
const { user, isAuthenticated, currentEntity, logout } = useAuth()
|
|
|
|
return (
|
|
<div>
|
|
{isAuthenticated && <p>Welcome, {user?.name}!</p>}
|
|
<button onClick={logout}>Log Out</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
### useNavigation Hook (`/src/hooks/use-navigation.ts`)
|
|
|
|
```typescript
|
|
import { useNavigation } from '@/hooks/use-navigation'
|
|
|
|
function MyComponent() {
|
|
const { currentView, navigateTo } = useNavigation()
|
|
|
|
return (
|
|
<button onClick={() => navigateTo('dashboard')}>
|
|
Go to Dashboard
|
|
</button>
|
|
)
|
|
}
|
|
```
|
|
|
|
### useReduxNotifications Hook (`/src/hooks/use-redux-notifications.ts`)
|
|
|
|
```typescript
|
|
import { useReduxNotifications } from '@/hooks/use-redux-notifications'
|
|
|
|
function MyComponent() {
|
|
const { notifications, unreadCount, addNotification, markAsRead } = useReduxNotifications()
|
|
|
|
const handleAction = () => {
|
|
addNotification({
|
|
type: 'success',
|
|
title: 'Success',
|
|
message: 'Action completed successfully',
|
|
})
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<p>Unread: {unreadCount}</p>
|
|
{notifications.map(n => (
|
|
<div key={n.id} onClick={() => markAsRead(n.id)}>
|
|
{n.title}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Use typed hooks**: Always use `useAppSelector` and `useAppDispatch` instead of the untyped versions from `react-redux`
|
|
|
|
2. **Create custom hooks**: Wrap common Redux patterns in custom hooks for reusability and cleaner components
|
|
|
|
3. **Keep slices focused**: Each slice should manage a single domain of state
|
|
|
|
4. **Use Redux DevTools**: The store is configured with Redux DevTools support for debugging
|
|
|
|
5. **Immutable updates**: Redux Toolkit uses Immer internally, so you can write "mutating" code in reducers that is automatically converted to immutable updates
|
|
|
|
6. **Async operations**: For async operations, consider using Redux Toolkit's `createAsyncThunk` or handle them in components/custom hooks
|
|
|
|
## Example: Complete Component with Redux
|
|
|
|
```typescript
|
|
import { useAppSelector, useAppDispatch } from '@/store/hooks'
|
|
import { setTimesheets, addTimesheet } from '@/store/slices/timesheetsSlice'
|
|
import { addNotification } from '@/store/slices/notificationsSlice'
|
|
import { Button } from '@/components/ui/button'
|
|
|
|
export function TimesheetList() {
|
|
const dispatch = useAppDispatch()
|
|
const timesheets = useAppSelector(state => state.timesheets.timesheets)
|
|
const loading = useAppSelector(state => state.timesheets.loading)
|
|
|
|
const handleAddTimesheet = () => {
|
|
const newTimesheet = {
|
|
id: `TS-${Date.now()}`,
|
|
workerName: 'New Worker',
|
|
status: 'pending',
|
|
// ... other fields
|
|
}
|
|
|
|
dispatch(addTimesheet(newTimesheet))
|
|
dispatch(addNotification({
|
|
id: `notif-${Date.now()}`,
|
|
type: 'success',
|
|
title: 'Timesheet Added',
|
|
message: 'New timesheet created successfully',
|
|
timestamp: new Date().toISOString(),
|
|
read: false,
|
|
}))
|
|
}
|
|
|
|
if (loading) return <div>Loading...</div>
|
|
|
|
return (
|
|
<div>
|
|
<Button onClick={handleAddTimesheet}>Add Timesheet</Button>
|
|
{timesheets.map(ts => (
|
|
<div key={ts.id}>{ts.workerName}</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
## Migration from useState to Redux
|
|
|
|
For existing components using local state, follow this pattern:
|
|
|
|
**Before (local state):**
|
|
```typescript
|
|
const [currentView, setCurrentView] = useState('dashboard')
|
|
```
|
|
|
|
**After (Redux):**
|
|
```typescript
|
|
const currentView = useAppSelector(state => state.ui.currentView)
|
|
const dispatch = useAppDispatch()
|
|
|
|
// To update:
|
|
dispatch(setCurrentView('timesheets'))
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
Consider adding these Redux features as the application grows:
|
|
|
|
- **Redux Persist**: Persist state to localStorage/sessionStorage
|
|
- **RTK Query**: For API data fetching and caching
|
|
- **createAsyncThunk**: For complex async operations
|
|
- **Entity Adapters**: For normalized state management of collections
|