Flashcard Application

The  Flashcards App which designed for authenticated users features a streamlined and user-friendly interface. At the core of the app is a secure user authentication system, allowing for safe sign-up and login, along with profile management options. Once logged in, users are greeted with a dashboard that showcases an overview of their flashcard decks and recent activities.

Deck management is a key component, offering the ability to create new decks for various subjects, view and edit existing decks, and organize them for efficient study. Within each deck, users can add, view, and edit individual flashcards, which are designed with a flip mechanism to display questions and answers.

Flashcard Application

				
					Github Link: https://github.com/suha-psms/Flashcards.git

app/src/lib/api.ts 

import { User, Deck, DeckWithUserData, CardType } from "./types";
import {
  getAuthenticatedUser,
  getAuthenticatedUserToken,
  removeAuthenticatedUserToken,
  storeAuthenticatedUserToken,
} from "./auth";

const API_URL = import.meta.env.VITE_API_URL;

export const fetchDeckById = async (id: string): Promise => {
  const response = await fetch(`${API_URL}/decks/${id}?withUserData=true`, {
    method: "GET",
  });
  const responseJson = await response.json();

  if (!response.ok) {
    throw new Error(
      `Error: ${response.status} - ${
        responseJson.message || response.statusText
      }`,
    );
  }

  return responseJson.data;
};

// Fetch all decks with user data
export const fetchDecks = async (): Promise => {
  const token = getAuthenticatedUserToken();
  const response = await fetch(`${API_URL}/decks?withUserData=true`, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
  });
  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }

  return responseJson.data;
};

//delete deck given its id
export const deleteDeck = async (id: string): Promise => {
  const token = getAuthenticatedUserToken();
  const response = await fetch(`${API_URL}/decks/${id}`, {
    method: "DELETE",
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });
  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }
};

// Create a deck
export const createDeck = async (
  title: string,
  image?: string,
): Promise => {
  const user = getAuthenticatedUser();
  const token = getAuthenticatedUserToken();

  const response = await fetch(`${API_URL}/decks`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ title, image }),
  });

  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }

  return {
    ...responseJson.data,
    user: user,
  };
};

// Update a deck
export const updateOrigDeck = async (
  id: string,
  title: string,
  image?: string,
): Promise => {
  const token = getAuthenticatedUserToken();
  const API_URL = import.meta.env.VITE_API_URL;
  const response = await fetch(`${API_URL}/decks/${id}`, {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ title, image }),
  });

  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }

  return responseJson.data;
};

export const login = async (
  username: string,
  password: string,
): Promise => {
  const response = await fetch(`${API_URL}/users/login`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ username, password }),
  });

  const responseJson = await response.json();

  if (!response.ok) {
    throw new Error(
      `Error: ${response.status} - ${
        responseJson.message || response.statusText
      }`,
    );
  }

  const { access_token } = responseJson.data;

  if (!access_token) {
    throw new Error("Authentication token is missing from the response!");
  }

  storeAuthenticatedUserToken(access_token);
  const user = getAuthenticatedUser();
  return user;
};

export const logout = async (): Promise => {
  removeAuthenticatedUserToken();
};

export const register = async (
  username: string,
  password: string,
  displayName: string,
  avatar?: string,
): Promise => {
  const response = await fetch(`${API_URL}/users/register`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ username, password, displayName, avatar }),
  });

  const responseJson = await response.json();

  if (!response.ok) {
    throw new Error(
      `Error: ${response.status} - ${
        responseJson.message || response.statusText
      }`,
    );
  }
};

const handleError = async (response: Response, message?: string) => {
  if (response.status === 401) {
    removeAuthenticatedUserToken();
    throw new Error("Your session has expired. Please login again.");
  }

  throw new Error(
    `Error: ${response.status} - ${message || response.statusText}`,
  );
};

export const fetchCards = async (deckId: string): Promise => {
  const token = getAuthenticatedUserToken();
  const response = await fetch(`${API_URL}/decks/${deckId}/cards`, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });
  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }

  return responseJson.data;
};

export const createCard = async (
  deckId: string,
  front: string,
  back: string,
): Promise => {
  const token = getAuthenticatedUserToken();
  const response = await fetch(`${API_URL}/decks/${deckId}/cards`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ front, back }),
  });

  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }

  return responseJson.data;
};

export const updateOldCard = async (
  deckId: string,
  cardId: string,
  front: string,
  back: string,
): Promise => {
  const token = getAuthenticatedUserToken();
  const response = await fetch(`${API_URL}/decks/${deckId}/cards/${cardId}`, {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ front, back }),
  });

  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }

  return responseJson.data;
};

export const deleteCard = async (
  deckId: string,
  cardId: string,
): Promise => {
  const token = getAuthenticatedUserToken();
  const response = await fetch(`${API_URL}/decks/${deckId}/cards/${cardId}`, {
    method: "DELETE",
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });

  const responseJson = await response.json();

  if (!response.ok) {
    handleError(response, responseJson.message);
  }
};