Skip to content

RednGift Frontend Overview

RednGift is a web platform that simplifies organizing gift exchanges and Secret Santa events. The application enables users to:

  • Create and manage gift exchange groups (Secret Santa)
  • Build and share wishlists with items they want to receive
  • Invite participants via phone number or shareable link
  • Automatically perform Secret Santa raffles (matching)
  • View matched participant’s wishlists while maintaining anonymity
  • Communicate with matched participants via real-time chat
  • Browse trending gift items for inspiration

Target users: Individuals organizing gift exchanges for friends, family, or coworkers.

Non-goals:

  • Payment processing or e-commerce transactions
  • Physical gift delivery or logistics
  • Public marketplace for selling items
┌─────────────────────────────────────────────────────────┐
│ Next.js App Router │
│ ┌────────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ Auth Pages │ │ Home Pages│ │ Invite Pages │ │
│ │ /auth/* │ │ /(home)/* │ │ /invite/[slug] │ │
│ └────────────┘ └───────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────┼─────────────────┐
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌─────▼──────┐
│ Redux │ │ Auth │ │ WebSocket │
│ Store │ │ Context │ │ Client │
│ (State) │ │ (JWT) │ │ (Real-time)│
└────┬────┘ └─────┬─────┘ └─────┬──────┘
│ │ │
└─────────────────┼─────────────────┘
┌─────▼──────┐
│ Handlers │
│ (API Layer)│
└─────┬──────┘
┌─────▼──────────┐
│ REST API │
│ redngift-ws │
│ (Backend) │
└────────────────┘
  1. Server/Client separation: Next.js App Router with ‘use client’ for interactive components
  2. State persistence: Redux Toolkit with redux-persist for offline resilience
  3. Real-time updates: WebSocket singleton for chat and notifications
  4. Authentication: JWT tokens stored in localStorage with automatic session management
  5. Error tracking: Sentry integration across all layers
src/
├── app/ # Next.js 13+ App Router pages
│ ├── (home)/ # Authenticated routes (layout with AuthGuard)
│ ├── auth/ # Authentication pages
│ └── invite/ # Public invitation acceptance pages
├── auth/ # Authentication logic
│ ├── context/ # AuthProvider (JWT) and WebSocketProvider
│ └── guard/ # Route guards (AuthGuard, GuestGuard)
├── components/ # Reusable UI components
├── layouts/ # Page layouts (home, auth, compact)
├── sections/ # Feature-specific page sections
│ ├── grupo/ # Group management views
│ ├── wishlist/ # Wishlist views
│ └── mensajes/ # Chat/messaging views
├── services/ # API layer
│ └── handlers/ # Domain-specific API handlers
├── types/ # TypeScript type definitions
├── utils/ # Utilities and Redux store
│ └── redux/ # Redux slices and store configuration
├── theme/ # Material-UI theme customization
└── routes/ # Route path definitions and hooks
Terminal window
# Development
yarn dev # Start dev server on port 8083
yarn dev:ts # Dev server + TypeScript watch mode
# Production
yarn build # Build for production
yarn start # Start production server
# Quality
yarn lint # Run ESLint
yarn lint:fix # Auto-fix linting issues
yarn prettier # Format code with Prettier
yarn ts # TypeScript type checking
yarn ts:watch # Watch mode type checking
# Maintenance
yarn rm:all # Clean all build artifacts and dependencies
yarn re:start # Fresh install and dev
yarn re:build # Fresh install and build
  • Next.js 13.5: React framework with App Router, SSR, and static generation
  • React 18.2: UI library with hooks and concurrent features
  • TypeScript 5.2: Static typing and enhanced IDE support
  • Redux Toolkit 1.9: Modern Redux with RTK Query
  • Redux Persist 6.0: Automatic state persistence to localStorage
  • React Redux 8.1: React bindings for Redux
  • Material-UI (MUI) 5.14: Component library with custom theme
  • Emotion 11: CSS-in-JS styling solution
  • Styled Components 6.0: Additional styling for custom components
  • Framer Motion 10: Animation library for transitions
  • React Hook Form 7.47: Performant form management
  • Yup 1.3: Schema validation
  • @hookform/resolvers: Yup integration for RHF
  • Axios 1.5: HTTP client with interceptors
  • WebSocket: Native WebSocket for real-time messaging
  • JWT Decode 4.0: Token parsing and validation
  • Sentry 7.81: Error tracking and performance monitoring
  • Hotjar: User behavior analytics and heatmaps
  • Google Analytics: Web analytics (gtag.js)
  • ESLint 8.50: Code linting with Airbnb config
  • Prettier 3.0: Code formatting
  • TypeScript ESLint 6.7: TypeScript-specific linting rules
  • CDN: Image hosting at cdn.rnb.la and img-s.rnb.la
  • WebSocket Server: wss://redngift-ws.rnb.la/connect
  • REST API: Configured via NEXT_PUBLIC_HOST_API environment variable

To add a new feature (e.g., “Gift Recommendations”):

  1. Define domain types in src/types/:
src/types/recommendations.types.ts
export interface Recommendation {
id: number;
itemId: number;
score: number;
reason: string;
}
  1. Create API handler in src/services/handlers/:
src/services/handlers/recommendations/recommendationsHandlers.ts
import { getRequest } from 'src/services/httpClient/httpClient';
const getRecommendations = async (userId: number) => {
const res = await getRequest(`recommendations/${userId}`);
return res.data;
};
export const recommendationsHandlers = {
getRecommendations,
};
  1. Create Redux slice in src/utils/redux/slices/:
src/utils/redux/slices/recommendationsSlice.ts
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchRecommendations = createAsyncThunk(
'recommendations/fetch',
async (userId: number) => {
return await recommendationsHandlers.getRecommendations(userId);
}
);
const recommendationsSlice = createSlice({
name: 'recommendations',
initialState: { items: [], loading: false },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchRecommendations.pending, (state) => {
state.loading = true;
})
.addCase(fetchRecommendations.fulfilled, (state, action) => {
state.items = action.payload;
state.loading = false;
});
},
});
export default recommendationsSlice.reducer;
  1. Register slice in root reducer:
src/utils/redux/root-reducer.ts
import recommendationsReducer from './slices/recommendationsSlice';
export const rootReducer = combineReducers({
// ... existing slices
recommendations: persistReducer(persistConfig('recommendations'), recommendationsReducer),
});
  1. Create page section in src/sections/:
src/sections/recommendations/recommendations-view.tsx
'use client';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'src/utils/redux/store';
import { fetchRecommendations } from 'src/utils/redux/slices/recommendationsSlice';
export default function RecommendationsView() {
const dispatch = useDispatch();
const { items, loading } = useSelector((state) => state.recommendations);
useEffect(() => {
dispatch(fetchRecommendations(userId));
}, [dispatch]);
return <div>{/* Render recommendations */}</div>;
}
  1. Create route in src/app/(home)/:
// src/app/(home)/recommendations/page.tsx
import RecommendationsView from 'src/sections/recommendations/recommendations-view';
export default function RecommendationsPage() {
return <RecommendationsView />;
}
  1. Add path definition in src/routes/paths.ts:
export const paths = {
home: {
// ... existing paths
recommendations: `${ROOTS.HOME}recommendations`,
},
};
  • Write unit tests for Redux slices (actions, reducers, selectors)
  • Test API handlers with mock responses
  • Test React components with React Testing Library
  • Integration tests for critical user flows

Assumption: Testing infrastructure not yet configured; add Jest and React Testing Library as needed.

  • Authentication method: JWT tokens issued by backend after magic link login
  • Token storage: localStorage (key: accessToken)
  • Token refresh: Not implemented; users must re-authenticate after expiration
  • Route protection: AuthGuard wraps authenticated routes, redirects to /auth/login if unauthenticated
  • API authorization: Axios interceptor attaches Authorization: Bearer <token> header to all requests
  • PII collected: User name, email, phone number, profile photo
  • PII storage: Backend only; frontend caches user data in Redux (ephemeral)
  • Image uploads: Sent to backend, which handles CDN upload
  • Third-party tracking: Sentry (error metadata), Hotjar (anonymized sessions), Google Analytics (pageviews)
  • Data retention: Redux state cleared on logout; localStorage token removed
  • XSS protection: React’s default escaping; use dangerouslySetInnerHTML only with sanitized content
  • CSRF: Not applicable (JWT in localStorage, not cookies)
  • Sensitive data in logs: Sentry captures exceptions; avoid logging tokens or passwords
  • Content Security Policy: Not configured; consider adding CSP headers in production

Assumption: Backend handles input validation, rate limiting, and SQL injection prevention.

  • Platform: Vercel (automatic deploys from Git)
  • Environments:
    • Development: Local (yarn dev)
    • Preview: Vercel preview deployments for PRs
    • Production: Vercel production deployment from main branch
  • Environment variables: Configured in Vercel dashboard
    • NEXT_PUBLIC_HOST_API: Backend API base URL
    • NEXT_PUBLIC_ASSETS_API: CDN base URL
    • Sentry DSN and auth tokens
    • Google Analytics ID
    • Hotjar site ID
  1. Merge feature branch to main via pull request
  2. Vercel automatically builds and deploys to production
  3. Sentry release tracking enabled via @sentry/nextjs plugin
  4. Source maps uploaded to Sentry for stack trace resolution

Assumption: No manual deployment steps; Vercel handles builds, CDN distribution, and rollbacks.

  • Error tracking: Sentry captures unhandled exceptions and API errors
  • Performance: Sentry performance monitoring for slow transactions
  • User analytics: Hotjar session recordings and Google Analytics pageviews
  • Logs: Next.js server logs available in Vercel dashboard