Best Practices for Frontend Implementation

  1. Authentication Flow

    1. Initial Setup: Store session tokens securely (localStorage for web, AsyncStorage for React Native)

    2. Token Management: Include tokens in Authorization headers for all authenticated endpoints

    3. Session Handling: Implement automatic logout on token expiration

    For Employers (Web Frontend)

    General Setup

    // API Base Configuration
    const API_BASE_URL = 'http://your-api-url';
    const getAuthHeaders = () => ({
      'Authorization': `Bearer ${localStorage.getItem('sessionKey')}`,
      'Content-Type': 'application/json'
    });

    File Upload Implementation

    // For multipart/form-data endpoints (signup, profile updates)
    const uploadWithFiles = async (endpoint, formData) => {
      const token = localStorage.getItem('sessionKey');
      
      const response = await fetch(`${API_BASE_URL}${endpoint}`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`
          // Don't set Content-Type for multipart/form-data
        },
        body: formData
      });
      
      return response.json();
    };

    Complete Authentication Implementation

    class AuthService {
      static async login(email, password) {
        const response = await fetch(`${API_BASE_URL}/login-employer`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email, password })
        });
        
        const data = await response.json();
        
        if (data.Status === 'Success') {
          localStorage.setItem('sessionKey', data['Debug Session Key']);
          localStorage.setItem('userId', data['App User ID']);
          return data;
        }
        throw new Error(data.Message);
      }
      
      static async logout() {
        const token = localStorage.getItem('sessionKey');
        await fetch(`${API_BASE_URL}/logout`, {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${token}` }
        });
        
        localStorage.removeItem('sessionKey');
        localStorage.removeItem('userId');
      }
    }

    Job Management Implementation

    class JobService {
      static async createJob(jobData) {
        const response = await fetch(`${API_BASE_URL}/create-jobs`, {
          method: 'POST',
          headers: getAuthHeaders(),
          body: JSON.stringify(jobData)
        });
        return response.json();
      }
      
      static async getJobs() {
        const response = await fetch(`${API_BASE_URL}/view-all-jobs`, {
          method: 'GET',
          headers: getAuthHeaders()
        });
        return response.json();
      }
      
      static async deleteJob(jobId) {
        const response = await fetch(`${API_BASE_URL}/delete-job/${jobId}`, {
          method: 'POST',
          headers: getAuthHeaders()
        });
        return response.json();
      }
    }

    For Employees (React Native)

    Dependencies Setup

    npm install @react-native-async-storage/async-storage
    expo install expo-image-picker expo-document-picker

    General Setup

    import AsyncStorage from '@react-native-async-storage/async-storage';
    import * as ImagePicker from 'expo-image-picker';
    import * as DocumentPicker from 'expo-document-picker';
    
    const API_BASE_URL = 'http://your-api-url';
    
    const getAuthHeaders = async () => {
      const token = await AsyncStorage.getItem('sessionKey');
      return {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      };
    };

    Complete Authentication Implementation

    class AuthService {
      static async login(email, password) {
        const response = await fetch(`${API_BASE_URL}/login-employee`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email, password })
        });
        
        const data = await response.json();
        
        if (data.Status === 'Success') {
          await AsyncStorage.setItem('sessionKey', data['Debug Session Key']);
          await AsyncStorage.setItem('userId', data['App User ID']);
          return data;
        }
        throw new Error(data.Message);
      }
      
      static async logout() {
        const token = await AsyncStorage.getItem('sessionKey');
        await fetch(`${API_BASE_URL}/logout`, {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${token}` }
        });
        
        await AsyncStorage.removeItem('sessionKey');
        await AsyncStorage.removeItem('userId');
      }
    }

    File Upload Implementation

    class FileService {
      static async pickImage() {
        const result = await ImagePicker.launchImageLibraryAsync({
          mediaTypes: ImagePicker.MediaTypeOptions.Images,
          allowsEditing: true,
          aspect: [1, 1],
          quality: 0.8,
        });
        
        if (!result.canceled) {
          return result.assets[0];
        }
        return null;
      }
      
      static async pickDocument() {
        const result = await DocumentPicker.getDocumentAsync({
          type: 'application/pdf',
          copyToCacheDirectory: false,
        });
        
        if (result.type === 'success') {
          return result;
        }
        return null;
      }
      
      static async uploadResume(resumeUri) {
        const token = await AsyncStorage.getItem('sessionKey');
        
        const formData = new FormData();
        formData.append('file', {
          uri: resumeUri,
          type: 'application/pdf',
          name: 'resume.pdf'
        });
        
        const response = await fetch(`${API_BASE_URL}/upload-resume`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'multipart/form-data'
          },
          body: formData
        });
        
        return response.json();
      }
    }

    Job Application Implementation

    class JobApplicationService {
      static async getRecommendations() {
        const headers = await getAuthHeaders();
        const response = await fetch(`${API_BASE_URL}/reco-jobs`, {
          method: 'GET',
          headers
        });
        return response.json();
      }
      
      static async applyForJob(jobId) {
        const headers = await getAuthHeaders();
        const response = await fetch(`${API_BASE_URL}/apply-job/${jobId}`, {
          method: 'POST',
          headers
        });
        return response.json();
      }
      
      static async getApplicationHistory() {
        const headers = await getAuthHeaders();
        const response = await fetch(`${API_BASE_URL}/my-applications`, {
          method: 'GET',
          headers
        });
        return response.json();
      }
    }

    Error Handling Best Practices

    Standard Error Handler

    const handleApiError = (error) => {
      if (error.message.includes('401')) {
        // Redirect to login
        window.location.href = '/login'; // Web
        // or navigation.navigate('Login'); // React Native
      } else if (error.message.includes('404')) {
        console.error('Resource not found');
      } else if (error.message.includes('500')) {
        console.error('Server error');
      } else {
        console.error('API Error:', error.message);
      }
    };

    File Validation

    const validateFile = (file, type = 'image', maxSize = 5) => {
      const maxSizeBytes = maxSize * 1024 * 1024; // Convert MB to bytes
      
      if (file.size > maxSizeBytes) {
        throw new Error(`File size must be less than ${maxSize}MB`);
      }
      
      if (type === 'image') {
        const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
        if (!allowedTypes.includes(file.type)) {
          throw new Error('Only JPG, JPEG, PNG, and GIF files are allowed');
        }
      } else if (type === 'pdf') {
        if (file.type !== 'application/pdf') {
          throw new Error('Only PDF files are allowed');
        }
      }
    };

    UI/UX Implementation Tips

    Loading States

    const [loading, setLoading] = useState(false);
    
    const handleSubmit = async () => {
      setLoading(true);
      try {
        await apiCall();
        // Success feedback
      } catch (error) {
        // Error feedback
      } finally {
        setLoading(false);
      }
    };

    Form Validation

    const validateForm = (formData) => {
      const errors = {};
      
      if (!formData.email) errors.email = 'Email is required';
      if (!formData.password || formData.password.length < 8) {
        errors.password = 'Password must be at least 8 characters';
      }
      
      return errors;
    };

Last updated