Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/features/admin/adminSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const selectAdminUsers = (state) => state.admin.users;
export const selectAdminSettings = (state) => state.admin.settings;
export const selectAdminLoading = (state) => state.admin.loading;
export const selectAdminError = (state) => state.admin.error;
19 changes: 19 additions & 0 deletions src/features/admin/adminSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
users: [],
settings: {},
loading: false,
error: null,
};

const adminSlice = createSlice({
name: 'admin',
initialState,
reducers: {
// Reducer placeholders
},
});


export default adminSlice.reducer;
12 changes: 12 additions & 0 deletions src/features/admin/adminThunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchAdminData = createAsyncThunk(
'admin/fetchData',
async (_, { rejectWithValue }) => {
try {
// Async logic placeholder
} catch (error) {
return rejectWithValue(error.message);
}
}
);
4 changes: 4 additions & 0 deletions src/features/auth/authSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const selectUser = (state) => state.auth.user;
export const selectIsAuthenticated = (state) => state.auth.isAuthenticated;
export const selectAuthLoading = (state) => state.auth.loading;
export const selectAuthError = (state) => state.auth.error;
19 changes: 19 additions & 0 deletions src/features/auth/authSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
user: null,
isAuthenticated: false,
loading: false,
error: null,
};

const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
// Reducer placeholders
},
});


export default authSlice.reducer;
12 changes: 12 additions & 0 deletions src/features/auth/authThunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

export const login = createAsyncThunk(
'auth/login',
async (credentials, { rejectWithValue }) => {
try {
// Async logic placeholder
} catch (error) {
return rejectWithValue(error.message);
}
}
);
3 changes: 3 additions & 0 deletions src/features/bookmarks/bookmarksSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const selectAllBookmarks = (state) => state.bookmarks.items;
export const selectBookmarksLoading = (state) => state.bookmarks.loading;
export const selectBookmarksError = (state) => state.bookmarks.error;
18 changes: 18 additions & 0 deletions src/features/bookmarks/bookmarksSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
items: [],
loading: false,
error: null,
};

const bookmarksSlice = createSlice({
name: 'bookmarks',
initialState,
reducers: {
// Reducer placeholders
},
});


export default bookmarksSlice.reducer;
12 changes: 12 additions & 0 deletions src/features/bookmarks/bookmarksThunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchBookmarks = createAsyncThunk(
'bookmarks/fetchAll',
async (_, { rejectWithValue }) => {
try {
// Async logic placeholder
} catch (error) {
return rejectWithValue(error.message);
}
}
);
3 changes: 3 additions & 0 deletions src/features/campaigns/campaignsSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const selectAllCampaigns = (state) => state.campaigns.items;
export const selectCampaignsLoading = (state) => state.campaigns.loading;
export const selectCampaignsError = (state) => state.campaigns.error;
18 changes: 18 additions & 0 deletions src/features/campaigns/campaignsSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
items: [],
loading: false,
error: null,
};

const campaignsSlice = createSlice({
name: 'campaigns',
initialState,
reducers: {
// Reducer placeholders
},
});


export default campaignsSlice.reducer;
12 changes: 12 additions & 0 deletions src/features/campaigns/campaignsThunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchCampaigns = createAsyncThunk(
'campaigns/fetchAll',
async (_, { rejectWithValue }) => {
try {
// Async logic placeholder
} catch (error) {
return rejectWithValue(error.message);
}
}
);
3 changes: 3 additions & 0 deletions src/features/dashboard/dashboardSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const selectDashboardStats = (state) => state.dashboard.stats;
export const selectDashboardLoading = (state) => state.dashboard.loading;
export const selectDashboardError = (state) => state.dashboard.error;
18 changes: 18 additions & 0 deletions src/features/dashboard/dashboardSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
stats: {},
loading: false,
error: null,
};

const dashboardSlice = createSlice({
name: 'dashboard',
initialState,
reducers: {
// Reducer placeholders
},
});


export default dashboardSlice.reducer;
12 changes: 12 additions & 0 deletions src/features/dashboard/dashboardThunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchDashboardStats = createAsyncThunk(
'dashboard/fetchStats',
async (_, { rejectWithValue }) => {
try {
// Async logic placeholder
} catch (error) {
return rejectWithValue(error.message);
}
}
);
3 changes: 3 additions & 0 deletions src/features/donations/donationsSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const selectDonationHistory = (state) => state.donations.history;
export const selectDonationsLoading = (state) => state.donations.loading;
export const selectDonationsError = (state) => state.donations.error;
18 changes: 18 additions & 0 deletions src/features/donations/donationsSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
history: [],
loading: false,
error: null,
};

const donationsSlice = createSlice({
name: 'donations',
initialState,
reducers: {
// Reducer placeholders
},
});


export default donationsSlice.reducer;
12 changes: 12 additions & 0 deletions src/features/donations/donationsThunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchDonations = createAsyncThunk(
'donations/fetchAll',
async (_, { rejectWithValue }) => {
try {
// Async logic placeholder
} catch (error) {
return rejectWithValue(error.message);
}
}
);
30 changes: 30 additions & 0 deletions src/store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Redux Store Configuration

This directory contains the Redux store configuration and global state management logic.

## Folder Structure Convention

We follow a feature-based folder structure for Redux slices. Each domain or feature should have its own directory under `src/features/`.

### Feature Folder Contents

Each feature folder (e.g., `src/features/auth/`) should contain:

1. **`[feature]Slice.js`**: Defines the Redux slice using `createSlice` from `@reduxjs/toolkit`. It should export the reducer as the default export and any actions as named exports.
2. **`[feature]Thunks.js`**: Contains async thunks created using `createAsyncThunk` for handling side effects and API calls.
3. **`[feature]Selectors.js`**: Contains memoized selectors (using `createSelector` if needed) to access specific parts of the feature's state.

## Adding a New Feature

To add a new feature to the Redux store:

1. Create a new directory in `src/features/` (e.g., `src/features/newFeature/`).
2. Add the slice, thunks, and selectors files as described above.
3. Import the new reducer in `src/store/rootReducer.js` and add it to the `combineReducers` call.

## Files in this Directory

- `index.js`: The main store configuration where the `rootReducer` is integrated.
- `rootReducer.js`: Combines all feature-level reducers into a single root reducer.
- `hooks.js`: Custom Redux hooks (`useAppDispatch`, `useAppSelector`) for better TypeScript/linting support.
- `README.md`: This documentation file.
6 changes: 1 addition & 5 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { configureStore } from '@reduxjs/toolkit';

// A simple placeholder reducer to fulfill the requirements until actual features are added
const rootReducer = (state = {}) => {
return state;
};
import rootReducer from './rootReducer';

export const store = configureStore({
reducer: rootReducer,
Expand Down
18 changes: 18 additions & 0 deletions src/store/rootReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { combineReducers } from '@reduxjs/toolkit';
import authReducer from '../features/auth/authSlice';
import campaignsReducer from '../features/campaigns/campaignsSlice';
import donationsReducer from '../features/donations/donationsSlice';
import dashboardReducer from '../features/dashboard/dashboardSlice';
import adminReducer from '../features/admin/adminSlice';
import bookmarksReducer from '../features/bookmarks/bookmarksSlice';

const rootReducer = combineReducers({
auth: authReducer,
campaigns: campaignsReducer,
donations: donationsReducer,
dashboard: dashboardReducer,
admin: adminReducer,
bookmarks: bookmarksReducer,
});

export default rootReducer;