All files / src/services reaction.ts

100% Statements 71/71
100% Branches 16/16
100% Functions 5/5
100% Lines 71/71

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 961x     1x 1x     1x 1x   1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                         1x 6x 6x 6x 6x 6x 6x 6x 6x   6x 6x 6x 6x 6x   6x 6x 6x 6x 6x 6x 6x 6x   4x   6x 3x 3x 3x 3x 3x 3x 2x 3x 3x 3x   1x 6x 6x 2x 2x 2x 2x 2x 1x 1x 2x 2x 6x 6x 6x 6x      
import { Effect, pipe, Schema } from 'effect';
 
// Constants
import { API_ROUTES } from '@/constants';
import { STATUS_CODE, STATUS_MESSAGES } from '@shared/constants';
 
// Types
import { ApiError, HttpMethod } from '@shared/types';
import { UserReaction } from '@/types';
 
export const ReactionRequestSchema = Schema.Struct({
  lunchMenuId: Schema.String.pipe(
    Schema.minLength(1, {
      message: () => STATUS_MESSAGES[STATUS_CODE.BAD_REQUEST]!,
    }),
  ),
  token: Schema.String.pipe(
    Schema.minLength(1, {
      message: () => STATUS_MESSAGES[STATUS_CODE.UNAUTHORIZED]!,
    }),
  ),
  type: Schema.Union(
    Schema.Literal(UserReaction.LIKE),
    Schema.Literal(UserReaction.DISLIKE),
  ),
});
 
interface ReactionServiceProps {
  lunchMenuId: string;
  token: string;
  type: UserReaction;
}
 
interface ReactionResponse {
  success: boolean;
  error?: ApiError | null;
}
 
const reactionService = async ({
  lunchMenuId,
  token,
  type,
}: ReactionServiceProps): Promise<ReactionResponse> =>
  Effect.runPromise(
    pipe(
      Effect.tryPromise({
        try: async () => {
          // Validate payload
          await Schema.decodeUnknown(ReactionRequestSchema)({
            lunchMenuId,
            token,
            type,
          });
 
          const response = await fetch(API_ROUTES.REACTION, {
            method: HttpMethod.POST,
            headers: {
              'Content-Type': 'application/json',
              Authorization: `Bearer ${token}`,
            },
            body: JSON.stringify({ lunchMenuId, type }),
          });
 
          const data = await response.json();
 
          if (!data || data.error) {
            return {
              success: false,
              error: {
                status: data?.error?.status ?? STATUS_CODE.BAD_REQUEST,
                message:
                  data?.error?.message ??
                  STATUS_MESSAGES[STATUS_CODE.BAD_REQUEST],
              },
            };
          }
 
          return { success: true };
        },
        catch: (error) => ({
          success: false,
          error: {
            status: STATUS_CODE.INTERNAL_SERVER_ERROR,
            message:
              error instanceof Error
                ? error.message
                : STATUS_MESSAGES[STATUS_CODE.INTERNAL_SERVER_ERROR],
          },
        }),
      }),
      Effect.catchAll((error) => Effect.succeed(error)),
    ),
  );
 
export { reactionService };