Fakultas Ilmu Komputer UI

Commit 44110602 authored by Muhammad Fairuzi Teguh's avatar Muhammad Fairuzi Teguh
Browse files

[REFACTOR] deprecate useDataApi in exchange of useQuery

parent 8e2a6f60
Pipeline #45177 passed with stages
in 2 minutes and 59 seconds
import { useReducer, useEffect, useCallback } from "react"
export const dataFetchReducer = (state, action) => {
switch (action.type) {
case "FETCH_INIT":
return {
...state,
isLoading: true,
isError: false,
}
case "FETCH_SUCCESS":
return {
...state,
isLoading: false,
isError: false,
data: action.payload,
}
case "FETCH_FAILURE":
return {
...state,
isLoading: false,
isError: true,
}
default:
throw new Error("Unknown action")
}
}
const useDataApi = (fetchApi, initialData, isMounted) => {
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
})
const fetchData = useCallback(async () => {
dispatch({ type: "FETCH_INIT" })
try {
const result = await fetchApi()
if (isMounted) {
dispatch({ type: "FETCH_SUCCESS", payload: result.data })
}
} catch (error) {
if (isMounted) {
dispatch({ type: "FETCH_FAILURE" })
}
}
}, [fetchApi, isMounted])
useEffect(() => {
fetchData()
}, [fetchData])
return [state, fetchData]
}
export default useDataApi
import { renderHook } from "@testing-library/react-hooks"
import useDataApi, { dataFetchReducer } from "./data-api"
describe("dataFetchReducer", () => {
it("Should throw error when given", () => {
expect(() => dataFetchReducer({}, "UNKNOWN_ACTION")).toThrow()
})
})
describe("useDataApi", () => {
it("Should not store data if already unmounted", async () => {
let resolvedPromise = () => Promise.resolve("The data")
const initialData = null
const { result, unmount } = renderHook(() =>
useDataApi(resolvedPromise, initialData)
)
unmount()
expect(result.current[0].data).toBe(initialData)
})
it("Should not dispatch failure if already unmounted", () => {
let rejectedPromise = () => Promise.reject(new Error("Dummy error"))
const { result, unmount } = renderHook(() =>
useDataApi(rejectedPromise, [])
)
unmount()
expect(result.current[0].isError).toBe(false)
})
})
import { useState, useEffect } from "react"
const useIsMounted = () => {
const [isMounted, setIsMounted] = useState(true)
useEffect(() => {
return () => {
setIsMounted(false)
}
}, [])
return isMounted
}
export default useIsMounted
import { fireEvent, screen, waitFor } from "@testing-library/react"
import { navigate } from "gatsby"
import React from "react"
import { postUserChangePassword } from "../api"
import { getListJadwalDonor, postUserChangePassword } from "../api"
import { doSuccessfulLogin } from "../hooks/authenticate.helper"
import Index from "./index"
import { render } from "../utils/test-util"
import ChangePasswordPage from "./changepassword"
import Index from "./index"
describe("Change Password", () => {
it("renders login before login", async () => {
......@@ -21,6 +21,7 @@ describe("Change Password", () => {
})
it("can be accessed from change profile modal", async () => {
getListJadwalDonor.mockResolvedValueOnce({ data: [] })
render(<Index />)
fireEvent.click(screen.getByText("Masuk"))
await doSuccessfulLogin()
......
import { faCircle } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import moment from "moment"
import React, { useCallback } from "react"
import React from "react"
import { Col, Row } from "react-bootstrap"
import { useQuery } from "react-query"
import { getListJadwalDonor } from "../api"
import ErrorRetry from "../components/error-retry"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Spinner from "../components/spinner"
import useDataApi from "../hooks/data-api"
import useIsMounted from "../hooks/useIsMounted"
import StokDonorChart from "../components/stokdonorchart"
import "./index.css"
......@@ -33,18 +32,15 @@ const Card = ({ header, color, children, className, ...other }) => (
)
const IndexPage = () => {
const isMounted = useIsMounted()
const getListJadwalDonorToday = useCallback(
() => getListJadwalDonor(moment().format("YYYY-MM-DD")),
[]
)
const [fetchJadwalDonorState, refetchJadwalDonorState] = useDataApi(
getListJadwalDonorToday,
[],
isMounted
)
const listJadwalDonor = fetchJadwalDonorState.data
const today = moment()
const {
status: statusListJadwalDonor,
data: dataListJadwalDonor,
refetch: refetchListJadwalDonor,
isFetching: isFetchingListJadwalDonor,
} = useQuery(["list-jadwal-donor-today"], queryKey =>
getListJadwalDonor(moment(today).format("YYYY-MM-DD"))
)
return (
<Layout navbar>
<SEO title="Home" />
......@@ -82,26 +78,29 @@ const IndexPage = () => {
)}`}
className="rounded"
>
{fetchJadwalDonorState.isLoading && <Spinner />}
{fetchJadwalDonorState.isError && (
<ErrorRetry retry={refetchJadwalDonorState} />
{isFetchingListJadwalDonor ? (
<Spinner />
) : statusListJadwalDonor === "error" ? (
<ErrorRetry retry={refetchListJadwalDonor} />
) : dataListJadwalDonor.data.length === 0 ? (
"Tidak ada jadwal donor hari ini"
) : (
dataListJadwalDonor.data.map((jadwalDonor, idx) => (
<div
className={`text-${
jadwalDonor.category === "terbuka" ? "red" : "blue"
}`}
key={idx}
>
<FontAwesomeIcon icon={faCircle} size="sm" className="mr-2" />
{`${jadwalDonor.location} | ${moment(
jadwalDonor.start_time
).format("HH:mm")} - ${moment(jadwalDonor.end_time).format(
"HH:mm"
)} | ${jadwalDonor.quota} orang`}
</div>
))
)}
{listJadwalDonor.length === 0 && "Tidak ada jadwal donor hari ini"}
{listJadwalDonor.map((jadwalDonor, idx) => (
<div
className={`text-${
jadwalDonor.category === "terbuka" ? "red" : "blue"
}`}
key={idx}
>
<FontAwesomeIcon icon={faCircle} size="sm" className="mr-2" />
{`${jadwalDonor.location} | ${moment(
jadwalDonor.start_time
).format("HH:mm")} - ${moment(jadwalDonor.end_time).format(
"HH:mm"
)} | ${jadwalDonor.quota} orang`}
</div>
))}
</Card>
</Col>
<Col xs="12" md="6" xl="6">
......
......@@ -39,6 +39,7 @@ describe(`Index`, () => {
})
it(`Show date for today`, async () => {
getListJadwalDonor.mockResolvedValueOnce({ data: [] })
const { getByText } = render(<Index />)
const today = moment()
await waitFor(() => {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment