diff --git a/src/config.js b/src/config.js index 4a0e1ac..ab82651 100644 --- a/src/config.js +++ b/src/config.js @@ -8,8 +8,7 @@ const config = { MIXPANEL_PROJECT_TOKEN: process.env.REACT_APP_MIXPANEL_PROJECT_TOKEN, }, production: { - // API_BASE_URL: process.env.REACT_APP_AWS_BACKEND_URL, - API_BASE_URL: "https://stg.api.susunjadwal.cs.ui.ac.id/susunjadwal/api", + API_BASE_URL: process.env.REACT_APP_AWS_BACKEND_URL, BASE_URL: "/", }, development: { diff --git a/src/containers/Admin/Feedbacks/feedback.js b/src/containers/Admin/Feedbacks/feedback.js new file mode 100644 index 0000000..22e1140 --- /dev/null +++ b/src/containers/Admin/Feedbacks/feedback.js @@ -0,0 +1,37 @@ +export const dummyFeedbacks = [ + { id: 1, username: 'farrel.altaf', rating: 5, feedback: 'Bagus banget inimah susun jadwal nggak membingungkan, makasih!', time: '17/04/2024 20:08', status: 'diproses' }, + { id: 2, username: 'johndoe', rating: 5, feedback: 'Sangat membantu, terima kasih!', time: '18/04/2024 10:15', status: 'diproses' }, + { id: 3, username: 'janedoe', rating: 5, feedback: 'Cukup membantu, tetapi bisa lebih baik.', time: '19/04/2024 14:23', status: 'belum_diproses' }, + { id: 4, username: 'alice', rating: 5, feedback: 'Luar biasa! Sangat merekomendasikan.', time: '20/04/2024 08:45', status: 'diproses' }, + { id: 5, username: 'bob', rating: 5, feedback: 'Tidak puas, banyak bug.', time: '21/04/2024 19:05', status: 'belum_diproses' }, + { id: 6, username: 'charlie', rating: 5, feedback: 'Bagus, tapi bisa lebih baik.', time: '22/04/2024 11:30', status: 'diproses' }, + { id: 7, username: 'dave', rating: 5, feedback: 'Kurang memuaskan.', time: '23/04/2024 17:50', status: 'belum_diproses' }, + { id: 8, username: 'eve', rating: 5, feedback: 'Biasa saja.', time: '24/04/2024 13:10', status: 'diproses' }, + { id: 9, username: 'frank', rating: 5, feedback: 'Luar biasa!', time: '25/04/2024 09:20', status: 'diproses' }, + { id: 10, username: 'grace', rating: 5, feedback: 'Sangat membantu, terima kasih!', time: '26/04/2024 16:40', status: 'diproses' }, + { id: 11, username: 'aldi.putra', rating: 5, feedback: 'Mantap, semoga kedepannya lebih bagus lagi.', time: '27/04/2024 10:30', status: 'diproses' }, + { id: 12, username: 'bella.rizky', rating: 5, feedback: 'Kurang suka, banyak yang kurang jelas.', time: '28/04/2024 14:50', status: 'belum_diproses' }, + { id: 13, username: 'cindy.sari', rating: 5, feedback: 'Biasa aja sih, tapi lumayan.', time: '29/04/2024 12:20', status: 'diproses' }, + { id: 14, username: 'doni.setiawan', rating: 5, feedback: 'Perfect! Gak ada duanya.', time: '30/04/2024 09:10', status: 'diproses' }, + { id: 15, username: 'erwin.pratama', rating: 5, feedback: 'Cukup oke, meskipun ada sedikit bug.', time: '01/05/2024 16:45', status: 'diproses' }, + { id: 16, username: 'fanny.febri', rating: 5, feedback: 'Gak sesuai ekspektasi, kecewa.', time: '02/05/2024 11:00', status: 'belum_diproses' }, + { id: 17, username: 'galih.eka', rating: 3, feedback: 'Lumayan, bisa diterima lah.', time: '03/05/2024 13:35', status: 'diproses' }, + { id: 18, username: 'hendra.satria', rating: 5, feedback: 'Bagus banget, sangat memudahkan.', time: '04/05/2024 15:20', status: 'diproses' }, + { id: 19, username: 'ika.putri', rating: 4, feedback: 'Bagus, tapi masih bisa ditingkatkan.', time: '05/05/2024 17:50', status: 'diproses' }, + { id: 20, username: 'jaka.saputra', rating: 2, feedback: 'Kurang memuaskan, banyak bug.', time: '06/05/2024 19:30', status: 'belum_diproses' }, + { id: 21, username: 'kenny.tan', rating: 3, feedback: 'Not bad, bisa lah.', time: '07/05/2024 21:10', status: 'diproses' }, + { id: 22, username: 'lina.agustina', rating: 4, feedback: 'Suka banget, sangat membantu.', time: '08/05/2024 08:50', status: 'diproses' }, + { id: 23, username: 'mario.gilang', rating: 5, feedback: 'Perfect, sangat memudahkan.', time: '09/05/2024 10:00', status: 'diproses' }, + { id: 24, username: 'nina.wulandari', rating: 2, feedback: 'Kurang jelas, banyak yang harus diperbaiki.', time: '10/05/2024 12:30', status: 'belum_diproses' }, + { id: 25, username: 'okky.ferdi', rating: 3, feedback: 'Lumayan, tapi banyak kekurangan.', time: '11/05/2024 14:10', status: 'diproses' }, + { id: 26, username: 'poppy.anggi', rating: 4, feedback: 'Bagus, saya suka.', time: '12/05/2024 16:00', status: 'diproses' }, + { id: 27, username: 'rizal.budi', rating: 1, feedback: 'Gak bagus, kecewa banget.', time: '13/05/2024 18:30', status: 'belum_diproses' }, + { id: 28, username: 'sandy.prayoga', rating: 5, feedback: 'Sangat memuaskan!', time: '14/05/2024 20:10', status: 'diproses' }, + { id: 29, username: 'tina.putri', rating: 4, feedback: 'Cukup membantu, terima kasih.', time: '15/05/2024 22:00', status: 'diproses' }, + { id: 30, username: 'utami.dewi', rating: 3, feedback: 'Biasa saja, masih bisa ditingkatkan.', time: '16/05/2024 08:10', status: 'diproses' }, +]; + +export const feedbackStats = [5, 4, 3, 2, 1].map(rating => ({ + rating, + count: dummyFeedbacks.filter(fb => fb.rating === rating).length, +})); diff --git a/src/containers/BuildSchedule/CourseClass.js b/src/containers/BuildSchedule/CourseClass.js index bdf8118..cb5b472 100644 --- a/src/containers/BuildSchedule/CourseClass.js +++ b/src/containers/BuildSchedule/CourseClass.js @@ -1,6 +1,6 @@ import React from "react"; import styled from "styled-components"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { useMixpanel } from "hooks/useMixpanel"; import { useSelector, useDispatch } from "react-redux"; import { addSchedule, removeSchedule } from "redux/modules/schedules"; import { useColorModeValue } from "@chakra-ui/react"; @@ -100,8 +100,7 @@ function CourseClass({ course, courseClass }) { dispatch(removeSchedule(item)); } else { dispatch(addSchedule(item)); - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("select_course"); + useMixpanel.track("select_course"); } }; diff --git a/src/containers/BuildSchedule/SelectMajor.js b/src/containers/BuildSchedule/SelectMajor.js index da612a8..d8cd2ad 100644 --- a/src/containers/BuildSchedule/SelectMajor.js +++ b/src/containers/BuildSchedule/SelectMajor.js @@ -1,5 +1,5 @@ import React from "react"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { useMixpanel } from "hooks/useMixpanel"; import { Flex } from "@chakra-ui/react"; import FACULTIES from "utils/faculty-base-additional-info.json"; import { useForm } from "react-hook-form"; @@ -29,13 +29,11 @@ function SelectMajor({ theme, isMobile, setMajorSelected, show }) { } useEffect(() => { - // TODO: Re-enable mixpanel or change to other analytics - // if (selectedFaculty) useMixpanel.track("select_faculty"); + if (selectedFaculty) useMixpanel.track("select_faculty"); }, [selectedFaculty]); useEffect(() => { - // TODO: Re-enable mixpanel or change to other analytics - // if (selectedMajorName) useMixpanel.track("select_prodi");/ + if (selectedMajorName) useMixpanel.track("select_prodi"); }, [selectedMajorName]); return ( diff --git a/src/containers/BuildSchedule/index.js b/src/containers/BuildSchedule/index.js index c2a1356..b3e363b 100644 --- a/src/containers/BuildSchedule/index.js +++ b/src/containers/BuildSchedule/index.js @@ -1,6 +1,6 @@ import React, { useEffect, useState, useCallback, useRef } from "react"; import { useSelector, useDispatch } from "react-redux"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { useMixpanel } from "hooks/useMixpanel"; import { Button, useColorModeValue, @@ -97,15 +97,13 @@ function BuildSchedule() { } }); - // TODO: Re-enable mixpanel or change to other analytics - // useEffect(() => { - // useMixpanel.track("open_buat_jadwal"); - // }, []); + useEffect(() => { + useMixpanel.track("open_buat_jadwal"); + }, []); useEffect(() => { if (isInitialMount.current) isInitialMount.current = false; - // TODO: Re-enable mixpanel or change to other analytics - // else useMixpanel.track("search_course"); + else useMixpanel.track("search_course"); }, [value]); return ( diff --git a/src/containers/Contributors/index.js b/src/containers/Contributors/index.js index f509699..4d9e89e 100644 --- a/src/containers/Contributors/index.js +++ b/src/containers/Contributors/index.js @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from "react"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { useMixpanel } from "hooks/useMixpanel"; import { Text, Box, Button, Flex, useColorModeValue } from "@chakra-ui/react"; import { ChevronLeftIcon } from "@chakra-ui/icons"; import { Link } from "react-router-dom"; @@ -36,8 +36,7 @@ const Contributors = () => { }, [fetchContributors]); useEffect(() => { - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("open_contributors"); + useMixpanel.track("open_contributors"); }, []); const MergeContributors = (contributors, otherContributors) => { @@ -91,8 +90,7 @@ const Contributors = () => { avatar={user.avatar_url} github={user.html_url} contributions={user.contributions} - // TODO: Re-enable mixpanel or change to other analytics - // onClick={() => useMixpanel.track("see_contributor_detail")} + onClick={() => useMixpanel.track("see_contributor_detail")} /> )); @@ -139,8 +137,7 @@ const Contributors = () => { useMixpanel.track("gabung_discord")} + onClick={() => useMixpanel.track("gabung_discord")} target="_blank" > diff --git a/src/containers/ViewSchedule/Schedule.js b/src/containers/ViewSchedule/Schedule.js index 972b835..1cfa2e7 100644 --- a/src/containers/ViewSchedule/Schedule.js +++ b/src/containers/ViewSchedule/Schedule.js @@ -5,7 +5,7 @@ import { useSelector } from "react-redux"; import { useColorModeValue } from "@chakra-ui/react"; import { useDisclosure } from "@chakra-ui/react"; import DetailsModal from "./DetailsModal"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { useMixpanel } from "hooks/useMixpanel"; const DAYS = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"]; const pad = (val) => { @@ -63,15 +63,13 @@ function Schedule({ ); const handleClickedCourse = (course) => { - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("open_course_detail"); + useMixpanel.track("open_course_detail"); setSelectedCourse(course); onOpen(); }; const handleCloseModal = () => { - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("close_course_detail"); + useMixpanel.track("close_course_detail"); onClose(); }; diff --git a/src/routes.js b/src/routes.js index 80e198a..c5958ce 100644 --- a/src/routes.js +++ b/src/routes.js @@ -22,6 +22,7 @@ import Contributors from "containers/Contributors"; import Feedback from "containers/Feedback"; import AdminLogin from "containers/Admin/Login"; import AdminFeedbacks from "containers/Admin/Feedbacks"; +import { validateAuth } from "utils/auth"; import withAnalytics from "utils/analytics"; @@ -105,6 +106,7 @@ function RoutesWithNavbar() { } function PrivateRoute({ component: Component, ...rest }) { + validateAuth(); const auth = useSelector((state) => state.auth); return ( diff --git a/src/services/api.js b/src/services/api.js index fc6621b..ab98351 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -137,3 +137,6 @@ export const updateReviewStatus = async (token, reviewId, status) => headers: { Authorization: `Bearer ${token}` }, }, ); + +export const validateToken = async () => + await instance.get("/auth/me"); \ No newline at end of file diff --git a/src/services/sso.js b/src/services/sso.js index 39d1ce3..2146716 100644 --- a/src/services/sso.js +++ b/src/services/sso.js @@ -1,5 +1,5 @@ import config from "config"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { useMixpanel } from "hooks/useMixpanel"; const { SSO_UI_URL, DOMAIN, BASE_URL } = config; @@ -7,13 +7,11 @@ const loginUrl = `${SSO_UI_URL}/login?service=${DOMAIN}${BASE_URL}`; const logoutUrl = `${SSO_UI_URL}/logout?url=${DOMAIN}${BASE_URL}`; export function redirectToSSOLogin() { - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("login"); + useMixpanel.track("login"); window.location.replace(loginUrl); } export function redirectToSSOLogout() { - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("logout"); + useMixpanel.track("logout"); window.location.replace(logoutUrl); } diff --git a/src/utils/auth.js b/src/utils/auth.js index f78606f..bfdcbdd 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -1,5 +1,5 @@ -import { setupAxiosInstance } from "services/api"; -// import { useMixpanel } from "hooks/useMixpanel"; +import { setupAxiosInstance, validateToken } from "services/api"; +import { useMixpanel } from "hooks/useMixpanel"; export function persistAuth(auth) { if (!auth) { @@ -7,8 +7,7 @@ export function persistAuth(auth) { } else { setupAxiosInstance(auth.token); localStorage.setItem("auth", JSON.stringify(auth)); - // TODO: Re-enable mixpanel or change to other analytics - // useMixpanel.track("login_successful"); + useMixpanel.track("login_successful"); } } @@ -37,3 +36,12 @@ export function loadCompletion() { const asJson = JSON.parse(persistedCompletion); return asJson; } + +export async function validateAuth() { + try{ + await validateToken(); + } catch (error) { + localStorage.clear(); + window.location.replace("/"); + } +} diff --git a/src/utils/date.js b/src/utils/date.js index a47023f..2997bb5 100644 --- a/src/utils/date.js +++ b/src/utils/date.js @@ -9,14 +9,12 @@ export function getDayOfCurrentWeek(day, date = new Date()) { } export const getFirstDateOfNthDayInAMonth = (dayOfTheWeek, month, year) => { - let tempDate = new Date(); + let tempDate = new Date(year, month, 1); tempDate.setHours(0, 0, 0, 0); - tempDate.setMonth(month); - tempDate.setYear(year); - tempDate.setDate(1); let day = tempDate.getDay(); - let toNextDay = day !== 0 ? dayOfTheWeek - day : 0; + let toNextDay = (dayOfTheWeek - day + 7) % 7; + tempDate.setDate(tempDate.getDate() + toNextDay); return tempDate;