diff --git a/src/components/domains/ActivityItem/index.tsx b/src/components/domains/ActivityItem/index.tsx
index 426a1fc..d4b6fbb 100644
--- a/src/components/domains/ActivityItem/index.tsx
+++ b/src/components/domains/ActivityItem/index.tsx
@@ -1,33 +1,33 @@
-import { captureException } from '@sentry/react';
+import { captureException } from '@sentry/react'
-import type { ActivityType } from '@/types';
+import type { ActivityType } from '@/types'
-import { ReactComponent as CheckIcon } from '@/assets/circle_check.svg';
-import { ReactComponent as XMarkIcon } from '@/assets/circle_x.svg';
-import { ReactComponent as StopwatchIcon } from '@/assets/stopwatch.svg';
-import ActivityTag from '@/components/domains/ActivityTag';
-import { convertDateTime, timeFormat } from '@/utils';
+import { ReactComponent as CheckIcon } from '@/assets/circle_check.svg'
+import { ReactComponent as XMarkIcon } from '@/assets/circle_x.svg'
+import { ReactComponent as StopwatchIcon } from '@/assets/stopwatch.svg'
+import ActivityTag from '@/components/domains/ActivityTag'
+import { convertDateTime, timeFormat } from '@/utils'
type Props = {
- activity: ActivityType;
- courseName: string;
-};
+ activity: ActivityType
+ courseName: string
+}
const Icon = ({ type }: { type: 'check' | 'x' | 'stopwatch' }) =>
({
check: ,
x: ,
stopwatch: ,
- }[type]);
+ }[type])
const ActivityItem = ({ activity, courseName }: Props) => {
- const { type, title, endAt, id } = activity;
+ const { type, title, endAt, id } = activity
- if (!title) captureException(new Error('[Warning] Activity title is empty'));
- if (!endAt) captureException(new Error('[Warning] Activity endAt is empty'));
- if (!id) captureException(new Error('[Warning] Activity id is empty'));
+ if (!title) captureException(new Error('[Warning] Activity title is empty'))
+ if (!endAt) captureException(new Error('[Warning] Activity endAt is empty'))
+ if (!id) captureException(new Error('[Warning] Activity id is empty'))
- const isAssignment = type === 'assignment';
+ const isAssignment = type === 'assignment'
return (
{
{timeFormat(endAt)}
- );
-};
+ )
+}
-export default ActivityItem;
+export default ActivityItem
diff --git a/src/components/domains/ActivityList/index.tsx b/src/components/domains/ActivityList/index.tsx
index b1ad88a..1bef976 100644
--- a/src/components/domains/ActivityList/index.tsx
+++ b/src/components/domains/ActivityList/index.tsx
@@ -1,12 +1,12 @@
-import type { ActivityType, Course } from '@/types';
+import type { ActivityType, Course } from '@/types'
-import ActivityItem from '@/components/domains/ActivityItem';
-import FlexCenterDiv from '@/components/uis/FlexCenterDiv';
+import ActivityItem from '@/components/domains/ActivityItem'
+import FlexCenterDiv from '@/components/uis/FlexCenterDiv'
type Props = {
- filteredActivityList: ActivityType[];
- courseList: Course[];
-};
+ filteredActivityList: ActivityType[]
+ courseList: Course[]
+}
const ActivityList = ({ filteredActivityList, courseList }: Props) => {
if (!filteredActivityList.length)
@@ -14,7 +14,7 @@ const ActivityList = ({ filteredActivityList, courseList }: Props) => {
과제가 없습니다.
- );
+ )
return (
{
/>
))}
- );
-};
+ )
+}
-export default ActivityList;
+export default ActivityList
diff --git a/src/components/domains/ActivityTag/index.tsx b/src/components/domains/ActivityTag/index.tsx
index 9bdcd33..d489fbd 100644
--- a/src/components/domains/ActivityTag/index.tsx
+++ b/src/components/domains/ActivityTag/index.tsx
@@ -1,5 +1,5 @@
interface ActivityTagProps {
- type: 'assignment' | 'video';
+ type: 'assignment' | 'video'
}
const ActivityTag = ({ type }: ActivityTagProps) => {
const status = {
@@ -11,7 +11,7 @@ const ActivityTag = ({ type }: ActivityTagProps) => {
color: 'bg-black',
text: '녹화강의',
},
- }[type];
+ }[type]
return (
{
>
{status.text}
- );
-};
+ )
+}
-export default ActivityTag;
+export default ActivityTag
diff --git a/src/components/domains/ContentModal/hooks/useFetchData.ts b/src/components/domains/ContentModal/hooks/useFetchData.ts
index 6770765..1b9fb32 100644
--- a/src/components/domains/ContentModal/hooks/useFetchData.ts
+++ b/src/components/domains/ContentModal/hooks/useFetchData.ts
@@ -1,47 +1,47 @@
-import { useState } from 'react';
+import { useState } from 'react'
-import type { ActivityType, Course } from '@/types';
+import type { ActivityType, Course } from '@/types'
-import { getActivities, getCourses } from '@/services';
-import { allProgress } from '@/utils';
+import { getActivities, getCourses } from '@/services'
+import { allProgress } from '@/utils'
type dataType = {
- courseList: Course[];
- activityList: ActivityType[];
- updateAt: number;
-};
+ courseList: Course[]
+ activityList: ActivityType[]
+ updateAt: number
+}
const useFetchData = () => {
- const [pos, setPos] = useState(0);
+ const [pos, setPos] = useState(0)
const [data, setData] = useState({
courseList: [{ id: '-1', title: '전체' }],
activityList: [],
updateAt: 0,
- });
+ })
const getData = async () => {
- const courses = await getCourses();
+ const courses = await getCourses()
const activities = await allProgress(
courses.map(course => getActivities(course.id)),
progress => setPos(progress),
- ).then(activities => activities.flat());
+ ).then(activities => activities.flat())
- const updateAt = new Date().getTime();
+ const updateAt = new Date().getTime()
setData({
courseList: [{ id: '-1', title: '전체' }, ...courses],
activityList: activities,
updateAt,
- });
+ })
- setPos(0);
+ setPos(0)
chrome.storage.local.set({
courses,
activities,
updateAt,
- });
- };
+ })
+ }
const getLocalData = () => {
chrome.storage.local.get(({ updateAt, courses, activities }) => {
@@ -49,11 +49,11 @@ const useFetchData = () => {
courseList: [{ id: '-1', title: '전체' }, ...courses],
activityList: activities,
updateAt,
- });
- });
- };
+ })
+ })
+ }
- return [getData, getLocalData, data, pos] as const;
-};
+ return [getData, getLocalData, data, pos] as const
+}
-export default useFetchData;
+export default useFetchData
diff --git a/src/components/domains/ContentModal/index.tsx b/src/components/domains/ContentModal/index.tsx
index 297c0bb..9551f3f 100644
--- a/src/components/domains/ContentModal/index.tsx
+++ b/src/components/domains/ContentModal/index.tsx
@@ -1,75 +1,75 @@
-import { forwardRef, useEffect, useState } from 'react';
-import { Tooltip } from 'react-tooltip';
+import { forwardRef, useEffect, useState } from 'react'
+import { Tooltip } from 'react-tooltip'
-import type { Course } from '@/types';
+import type { Course } from '@/types'
-import { ReactComponent as RefreshIcon } from '@/assets/refresh.svg';
-import { ReactComponent as SettingIcon } from '@/assets/setting.svg';
-import ActivityList from '@/components/domains/ActivityList';
-import useFetchData from '@/components/domains/ContentModal/hooks/useFetchData';
-import Filter from '@/components/uis/Filter';
-import FlexCenterDiv from '@/components/uis/FlexCenterDiv';
-import Modal from '@/components/uis/Modal';
-import ProgressBar from '@/components/uis/ProgressBar';
-import { REFRESH_TIME } from '@/constants';
-import useError from '@/hooks/useError';
-import useScrollLock from '@/hooks/useScrollLock';
-import filteredActivities from '@/utils/filteredActivityList';
+import { ReactComponent as RefreshIcon } from '@/assets/refresh.svg'
+import { ReactComponent as SettingIcon } from '@/assets/setting.svg'
+import ActivityList from '@/components/domains/ActivityList'
+import useFetchData from '@/components/domains/ContentModal/hooks/useFetchData'
+import Filter from '@/components/uis/Filter'
+import FlexCenterDiv from '@/components/uis/FlexCenterDiv'
+import Modal from '@/components/uis/Modal'
+import ProgressBar from '@/components/uis/ProgressBar'
+import { REFRESH_TIME } from '@/constants'
+import useError from '@/hooks/useError'
+import useScrollLock from '@/hooks/useScrollLock'
+import filteredActivities from '@/utils/filteredActivityList'
const status = [
{ id: 1, title: '진행중인 과제' },
{ id: 2, title: '모든 과제' },
-];
+]
type Props = {
- isOpen: boolean;
- onClick: (event: React.MouseEvent) => void;
-};
+ isOpen: boolean
+ onClick: (event: React.MouseEvent) => void
+}
const ContentModal = ({ isOpen, onClick }: Props, ref: React.Ref) => {
- const [selectedCourse, setSelectedCourse] = useState({ id: '-1', title: '전체' });
- const [statusType, setStatusType] = useState<{ id: number; title: string }>(status[0]);
- const [isRefresh, setIsRefresh] = useState(false);
- const [isChecked, setIsChecked] = useState(false);
+ const [selectedCourse, setSelectedCourse] = useState({ id: '-1', title: '전체' })
+ const [statusType, setStatusType] = useState<{ id: number; title: string }>(status[0])
+ const [isRefresh, setIsRefresh] = useState(false)
+ const [isChecked, setIsChecked] = useState(false)
- const { catchAsyncError } = useError();
- const { scrollLock, scrollUnlock } = useScrollLock();
- const [getData, getLocalData, data, pos] = useFetchData();
+ const { catchAsyncError } = useError()
+ const { scrollLock, scrollUnlock } = useScrollLock()
+ const [getData, getLocalData, data, pos] = useFetchData()
- const { courseList, activityList, updateAt } = data;
+ const { courseList, activityList, updateAt } = data
const filteredActivityList = filteredActivities(
activityList,
selectedCourse.id,
statusType.title,
isChecked,
- );
+ )
useEffect(() => {
- if (!isRefresh) return;
+ if (!isRefresh) return
getData()
.then(() => setIsRefresh(false))
- .catch(error => catchAsyncError(error));
- }, [isRefresh]);
+ .catch(error => catchAsyncError(error))
+ }, [isRefresh])
useEffect(() => {
- if (!isOpen) return;
- scrollLock();
+ if (!isOpen) return
+ scrollLock()
if (!isRefresh)
chrome.storage.local.get(['updateAt'], ({ updateAt }) => {
- if (!updateAt) return setIsRefresh(true);
+ if (!updateAt) return setIsRefresh(true)
- const diff = new Date().getTime() - updateAt;
- const isOverRefreshTime = diff > REFRESH_TIME;
+ const diff = new Date().getTime() - updateAt
+ const isOverRefreshTime = diff > REFRESH_TIME
if (!isOverRefreshTime) {
- getLocalData();
+ getLocalData()
} else {
- setIsRefresh(true);
+ setIsRefresh(true)
}
- });
+ })
- return scrollUnlock;
- }, [isOpen]);
+ return scrollUnlock
+ }, [isOpen])
return (
checked={isChecked}
onChange={() => setIsChecked(!isChecked)}
/>
- 미제출 과제만 보기
+ 미제출 과제만
@@ -144,7 +144,7 @@ const ContentModal = ({ isOpen, onClick }: Props, ref: React.Ref
- );
-};
+ )
+}
-export default forwardRef(ContentModal);
+export default forwardRef(ContentModal)
diff --git a/src/components/domains/OptionItem/index.tsx b/src/components/domains/OptionItem/index.tsx
index f4a8c31..1966ef2 100644
--- a/src/components/domains/OptionItem/index.tsx
+++ b/src/components/domains/OptionItem/index.tsx
@@ -1,25 +1,25 @@
-import { useState } from 'react';
+import { useState } from 'react'
-import Toggle from '@/components/uis/Toggle';
+import Toggle from '@/components/uis/Toggle'
interface OptionItemProps {
- text: string;
+ text: string
}
const OptionItem = ({ text }: OptionItemProps) => {
- const [isOn, setIsOn] = useState(false);
+ const [isOn, setIsOn] = useState(false)
const toggleSwitch = () => {
- setIsOn(prev => !prev);
+ setIsOn(prev => !prev)
// TODO: Save the option to the local storage
- };
+ }
return (
{text}
- );
-};
+ )
+}
-export default OptionItem;
+export default OptionItem
diff --git a/src/components/uis/Filter/index.tsx b/src/components/uis/Filter/index.tsx
index 6079594..ed738fd 100644
--- a/src/components/uis/Filter/index.tsx
+++ b/src/components/uis/Filter/index.tsx
@@ -1,25 +1,25 @@
-import { createContext, useContext, useState } from 'react';
+import { createContext, useContext, useState } from 'react'
-import { ReactComponent as CheckIcon } from '@/assets/check.svg';
-import { ReactComponent as DropdownIcon } from '@/assets/dropdown.svg';
-import { ReactComponent as DropupIcon } from '@/assets/dropup.svg';
-import Modal from '@/components/uis/Modal';
+import { ReactComponent as CheckIcon } from '@/assets/check.svg'
+import { ReactComponent as DropdownIcon } from '@/assets/dropdown.svg'
+import { ReactComponent as DropupIcon } from '@/assets/dropup.svg'
+import Modal from '@/components/uis/Modal'
-type valueType = { title: string; [key: string]: any };
+type valueType = { title: string; [key: string]: any }
type FilterProps = {
- value: valueType;
- onChange: React.Dispatch>;
- children: React.ReactNode;
- maxWidth?: string;
- hasBorder?: boolean;
-};
+ value: valueType
+ onChange: React.Dispatch>
+ children: React.ReactNode
+ maxWidth?: string
+ hasBorder?: boolean
+}
-const FilterDataContext = createContext | null>(null);
-const OpenClosedContext = createContext<{ isOpen: boolean } | null>(null);
+const FilterDataContext = createContext | null>(null)
+const OpenClosedContext = createContext<{ isOpen: boolean } | null>(null)
const Filter = ({ value, maxWidth, onChange, children, hasBorder = true }: FilterProps) => {
- const [isOpen, setIsOpen] = useState(false);
+ const [isOpen, setIsOpen] = useState(false)
return (
@@ -39,25 +39,25 @@ const Filter = ({ value, maxWidth, onChange, children, hasBorder = true }: Filte
- );
-};
+ )
+}
type FilterHeaderProps = {
- className?: string;
-};
+ className?: string
+}
const FilterHeader = ({ className }: FilterHeaderProps) => {
- const { value } = useContext(FilterDataContext);
- return {value.title}
;
-};
+ const { value } = useContext(FilterDataContext)
+ return {value.title}
+}
type FilterModalProps = {
- children: React.ReactNode;
- pos?: 'left' | 'right';
-};
+ children: React.ReactNode
+ pos?: 'left' | 'right'
+}
const FilterModal = ({ children, pos = 'right' }: FilterModalProps) => {
- const { isOpen } = useContext(OpenClosedContext);
+ const { isOpen } = useContext(OpenClosedContext)
return (
{
{children}
- );
-};
+ )
+}
type FilterItemProps = {
- item: valueType;
-};
+ item: valueType
+}
const FilterItem = ({ item }: FilterItemProps) => {
- const { value, onChange } = useContext(FilterDataContext);
- const isChecked = value === item;
+ const { value, onChange } = useContext(FilterDataContext)
+ const isChecked = value === item
const handleClick = () => {
- if (isChecked) return;
- onChange(item);
- };
+ if (isChecked) return
+ onChange(item)
+ }
return (
- );
-};
+ )
+}
-Filter.Header = FilterHeader;
-Filter.Modal = FilterModal;
-Filter.Item = FilterItem;
+Filter.Header = FilterHeader
+Filter.Modal = FilterModal
+Filter.Item = FilterItem
-export default Filter;
+export default Filter
diff --git a/src/components/uis/FlexCenterDiv/index.tsx b/src/components/uis/FlexCenterDiv/index.tsx
index 10649a2..d59274c 100644
--- a/src/components/uis/FlexCenterDiv/index.tsx
+++ b/src/components/uis/FlexCenterDiv/index.tsx
@@ -1,6 +1,6 @@
interface Props extends React.HTMLAttributes {
- className: string;
- children: React.ReactNode;
+ className: string
+ children: React.ReactNode
}
const FlexCenterDiv = ({ className, children, ...props }: Props) => {
@@ -8,7 +8,7 @@ const FlexCenterDiv = ({ className, children, ...props }: Props) => {
{children}
- );
-};
+ )
+}
-export default FlexCenterDiv;
+export default FlexCenterDiv
diff --git a/src/components/uis/Modal/index.tsx b/src/components/uis/Modal/index.tsx
index 04e9424..fd2501f 100644
--- a/src/components/uis/Modal/index.tsx
+++ b/src/components/uis/Modal/index.tsx
@@ -1,21 +1,21 @@
-import { AnimatePresence, motion } from 'framer-motion';
-import { forwardRef } from 'react';
+import { AnimatePresence, motion } from 'framer-motion'
+import { forwardRef } from 'react'
type ModalProps = {
- children: React.ReactNode;
- className?: string;
-};
+ children: React.ReactNode
+ className?: string
+}
const Modal = ({ className, children }: ModalProps) => {
- return {children}
;
-};
+ return {children}
+}
type ModalBackgroundProps = {
- isOpen: boolean;
- children: React.ReactNode;
- className?: string;
- onClick?: (e: React.MouseEvent) => void;
-};
+ isOpen: boolean
+ children: React.ReactNode
+ className?: string
+ onClick?: (e: React.MouseEvent) => void
+}
const ModalBackground = (
{ isOpen, children, className, onClick }: ModalBackgroundProps,
@@ -36,9 +36,9 @@ const ModalBackground = (
)}
- );
-};
+ )
+}
-Modal.Background = forwardRef(ModalBackground);
+Modal.Background = forwardRef(ModalBackground)
-export default Modal;
+export default Modal
diff --git a/src/components/uis/ProgressBar/index.tsx b/src/components/uis/ProgressBar/index.tsx
index 4d2dcdf..c79bc4f 100644
--- a/src/components/uis/ProgressBar/index.tsx
+++ b/src/components/uis/ProgressBar/index.tsx
@@ -1,16 +1,16 @@
type Props = {
- pos: number;
- max?: number;
-};
+ pos: number
+ max?: number
+}
const ProgressBar = ({ pos, max = 100 }: Props) => {
- const percent = (pos / max) * 100;
+ const percent = (pos / max) * 100
return (
- );
-};
+ )
+}
-export default ProgressBar;
+export default ProgressBar
diff --git a/src/components/uis/Toast/index.tsx b/src/components/uis/Toast/index.tsx
index 929b335..823966d 100644
--- a/src/components/uis/Toast/index.tsx
+++ b/src/components/uis/Toast/index.tsx
@@ -1,26 +1,26 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react'
-import Modal from '../Modal';
+import Modal from '../Modal'
type Props = {
- message: string;
- type: 'success' | 'error';
- delay?: number;
-};
+ message: string
+ type: 'success' | 'error'
+ delay?: number
+}
const Toast = ({ message, type, delay = 3000 }: Props) => {
- const [isOpen, setIsOpen] = useState(false);
+ const [isOpen, setIsOpen] = useState(false)
const toastColor = {
success: 'bg-green-500',
error: 'bg-red-500',
- };
+ }
useEffect(() => {
- setIsOpen(true);
- const timer = setTimeout(() => setIsOpen(false), delay);
- return () => clearTimeout(timer);
- }, []);
+ setIsOpen(true)
+ const timer = setTimeout(() => setIsOpen(false), delay)
+ return () => clearTimeout(timer)
+ }, [])
return (
@@ -30,7 +30,7 @@ const Toast = ({ message, type, delay = 3000 }: Props) => {
{message}
- );
-};
+ )
+}
-export default Toast;
+export default Toast
diff --git a/src/components/uis/Toggle/index.tsx b/src/components/uis/Toggle/index.tsx
index 7dddc49..429b054 100644
--- a/src/components/uis/Toggle/index.tsx
+++ b/src/components/uis/Toggle/index.tsx
@@ -1,8 +1,8 @@
-import { motion } from 'framer-motion';
+import { motion } from 'framer-motion'
interface ToggleProps {
- isOn: boolean;
- toggleSwitch: () => void;
+ isOn: boolean
+ toggleSwitch: () => void
}
const Toggle = ({ isOn, toggleSwitch }: ToggleProps) => {
@@ -10,7 +10,7 @@ const Toggle = ({ isOn, toggleSwitch }: ToggleProps) => {
type: 'spring',
stiffness: 700,
damping: 30,
- };
+ }
return (
{
transition={spring}
>
- );
-};
+ )
+}
-export default Toggle;
+export default Toggle
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 14797b9..a2cad00 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -1 +1 @@
-export const REFRESH_TIME = 1000 * 60 * 10; // 10분
+export const REFRESH_TIME = 1000 * 60 * 10 // 10분
diff --git a/src/content.tsx b/src/content.tsx
index 084cf5a..b903107 100644
--- a/src/content.tsx
+++ b/src/content.tsx
@@ -1,12 +1,12 @@
-import { createRoot } from 'react-dom/client';
+import { createRoot } from 'react-dom/client'
-import App from '@/pages/content/App';
+import App from '@/pages/content/App'
-import '@/styles/globals.css';
-import 'react-tooltip/dist/react-tooltip.css';
+import '@/styles/globals.css'
+import 'react-tooltip/dist/react-tooltip.css'
-const root = document.createElement('div');
-root.id = 'crx-root';
-document.body.append(root);
+const root = document.createElement('div')
+root.id = 'crx-root'
+document.body.append(root)
-createRoot(root).render();
+createRoot(root).render()
diff --git a/src/data/dummyData.ts b/src/data/dummyData.ts
index 8d81397..4eae201 100644
--- a/src/data/dummyData.ts
+++ b/src/data/dummyData.ts
@@ -1,4 +1,4 @@
-import type { ActivityType, Course } from '@/types';
+import type { ActivityType, Course } from '@/types'
export const courseData: Course[] = [
{
@@ -17,7 +17,7 @@ export const courseData: Course[] = [
id: '76094',
title: '고객가치',
},
-];
+]
export const ActivityData: ActivityType[] = [
{
@@ -399,4 +399,4 @@ export const ActivityData: ActivityType[] = [
title: '성적제출',
type: 'assignment',
},
-];
+]
diff --git a/src/global.d.ts b/src/global.d.ts
index 4cc07c1..d68059d 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -1,5 +1,5 @@
-import Chrome from 'chrome';
+import Chrome from 'chrome'
declare namespace chrome {
- export default Chrome;
+ export default Chrome
}
diff --git a/src/helpers/portal.ts b/src/helpers/portal.ts
index cce7e3e..81f1b5d 100644
--- a/src/helpers/portal.ts
+++ b/src/helpers/portal.ts
@@ -1,13 +1,13 @@
-import { createPortal } from 'react-dom';
+import { createPortal } from 'react-dom'
type Props = {
- elementId: string;
- children: React.ReactNode;
-};
+ elementId: string
+ children: React.ReactNode
+}
const Portal = ({ elementId, children }: Props) => {
- const el = document.getElementById(elementId) as HTMLElement;
- return createPortal(children, el);
-};
+ const el = document.getElementById(elementId) as HTMLElement
+ return createPortal(children, el)
+}
-export default Portal;
+export default Portal
diff --git a/src/hooks/useError.ts b/src/hooks/useError.ts
index c4865d7..077fadd 100644
--- a/src/hooks/useError.ts
+++ b/src/hooks/useError.ts
@@ -1,13 +1,13 @@
-import { useState } from 'react';
+import { useState } from 'react'
const useError = () => {
- const [error, setError] = useState(null);
+ const [error, setError] = useState(null)
const catchAsyncError = (error: Error) => {
- setError(error);
- };
+ setError(error)
+ }
- return { error, catchAsyncError };
-};
+ return { error, catchAsyncError }
+}
-export default useError;
+export default useError
diff --git a/src/hooks/useScrollLock.ts b/src/hooks/useScrollLock.ts
index 8a653d0..25ae26e 100644
--- a/src/hooks/useScrollLock.ts
+++ b/src/hooks/useScrollLock.ts
@@ -4,16 +4,16 @@ const useScrollLock = () => {
position: fixed;
top: -${window.scrollY}px;
overflow-y: scroll;
- width: 100%;`;
- };
+ width: 100%;`
+ }
const scrollUnlock = () => {
- const scrollY = document.body.style.top;
- document.body.style.cssText = '';
- window.scrollTo(0, parseInt(scrollY || '0', 10) * -1);
- };
+ const scrollY = document.body.style.top
+ document.body.style.cssText = ''
+ window.scrollTo(0, parseInt(scrollY || '0', 10) * -1)
+ }
- return { scrollLock, scrollUnlock };
-};
+ return { scrollLock, scrollUnlock }
+}
-export default useScrollLock;
+export default useScrollLock
diff --git a/src/pages/background/index.ts b/src/pages/background/index.ts
index 0cc61dc..30092e6 100644
--- a/src/pages/background/index.ts
+++ b/src/pages/background/index.ts
@@ -4,23 +4,23 @@ chrome.runtime.onInstalled.addListener(async () => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: cs.js,
- });
+ })
cs.css?.forEach(css => {
chrome.scripting.insertCSS({
target: { tabId: tab.id },
files: [css],
- });
- });
+ })
+ })
}
}
-});
+})
chrome.storage.onChanged.addListener((changes, areaName) => {
if (areaName === 'local') {
for (const key of Object.keys(changes)) {
- console.log(`storage.local.${key} changed`);
+ console.log(`storage.local.${key} changed`)
}
}
-});
+})
-export {};
+export {}
diff --git a/src/pages/content/App.tsx b/src/pages/content/App.tsx
index 0e5f923..447c866 100644
--- a/src/pages/content/App.tsx
+++ b/src/pages/content/App.tsx
@@ -1,32 +1,32 @@
-import { ErrorBoundary } from '@sentry/react';
-import { motion } from 'framer-motion';
-import { useRef, useState } from 'react';
+import { Box, useDisclosure } from '@chakra-ui/react'
+import { AnimatePresence } from 'framer-motion'
-import ContentModal from '@/components/domains/ContentModal';
-import Toast from '@/components/uis/Toast';
-import Portal from '@/helpers/portal';
+import ChakraMotion from '@/components/ChakraMotion'
+import ContentModal from '@/components/ContentModal'
export default function App() {
- const [isModalOpen, setIsModalOpen] = useState(false);
- const modalRef = useRef();
-
- const handleModalClick = (event: React.MouseEvent) => {
- if (event.target === modalRef.current) setIsModalOpen(false);
- };
+ const { isOpen, onOpen, onClose } = useDisclosure()
return (
-
-
setIsModalOpen(prev => !prev)}
- >
-
- }>
-
-
-
-
- );
+
+
+ {!isOpen && (
+
+ )}
+
+
+
+ )
}
diff --git a/src/pages/content/main.tsx b/src/pages/content/main.tsx
index 672847c..51caca1 100644
--- a/src/pages/content/main.tsx
+++ b/src/pages/content/main.tsx
@@ -1,4 +1,4 @@
-import { ChakraProvider } from '@chakra-ui/react'
+import { ChakraProvider, extendTheme } from '@chakra-ui/react'
import * as Sentry from '@sentry/react'
import { createRoot } from 'react-dom/client'
@@ -32,8 +32,19 @@ const modal = document.createElement('div')
modal.id = 'modal'
document.body.append(modal)
+const theme = extendTheme({
+ styles: {
+ global: {
+ p: {
+ margin: 0,
+ padding: 0,
+ },
+ },
+ },
+})
+
createRoot(root).render(
-
+
,
)
diff --git a/src/pages/options/Options.tsx b/src/pages/options/Options.tsx
index d1fb522..98e462e 100644
--- a/src/pages/options/Options.tsx
+++ b/src/pages/options/Options.tsx
@@ -1,6 +1,6 @@
-import packageJson from '../../../package.json';
+import packageJson from '../../../package.json'
-const { version } = packageJson;
+const { version } = packageJson
function Options() {
return (
@@ -17,7 +17,7 @@ function Options() {
version: {version}
- );
+ )
}
-export default Options;
+export default Options
diff --git a/src/pages/options/index.tsx b/src/pages/options/index.tsx
index 5f5e727..da15a04 100644
--- a/src/pages/options/index.tsx
+++ b/src/pages/options/index.tsx
@@ -1,7 +1,7 @@
-import { createRoot } from 'react-dom/client';
+import { createRoot } from 'react-dom/client'
-import Options from '@/pages/options/Options';
-import '@/styles/globals.css';
-import '@/styles/options.css';
+import Options from '@/pages/options/Options'
+import '@/styles/globals.css'
+import '@/styles/options.css'
-createRoot(document.getElementById('app-container') as HTMLElement).render();
+createRoot(document.getElementById('app-container') as HTMLElement).render()
diff --git a/src/pages/popup/Popup.tsx b/src/pages/popup/Popup.tsx
index aec9ae2..23f3fb2 100644
--- a/src/pages/popup/Popup.tsx
+++ b/src/pages/popup/Popup.tsx
@@ -1,8 +1,8 @@
-import { Tooltip } from 'react-tooltip';
+import { Tooltip } from 'react-tooltip'
-import { ReactComponent as FeedbackIcon } from '@/assets/feedback.svg';
-import { ReactComponent as GachonIcon } from '@/assets/gachon.svg';
-import { ReactComponent as GithubIcon } from '@/assets/github.svg';
+import { ReactComponent as FeedbackIcon } from '@/assets/feedback.svg'
+import { ReactComponent as GachonIcon } from '@/assets/gachon.svg'
+import { ReactComponent as GithubIcon } from '@/assets/github.svg'
function App() {
return (
@@ -36,7 +36,7 @@ function App() {
- );
+ )
}
-export default App;
+export default App
diff --git a/src/pages/popup/index.tsx b/src/pages/popup/index.tsx
index c514a59..238f6d5 100644
--- a/src/pages/popup/index.tsx
+++ b/src/pages/popup/index.tsx
@@ -1,7 +1,7 @@
-import { createRoot } from 'react-dom/client';
+import { createRoot } from 'react-dom/client'
-import Popup from '@/pages/popup/Popup';
-import '@/styles/globals.css';
-import 'react-tooltip/dist/react-tooltip.css';
+import Popup from '@/pages/popup/Popup'
+import '@/styles/globals.css'
+import 'react-tooltip/dist/react-tooltip.css'
-createRoot(document.getElementById('app-container') as HTMLElement).render();
+createRoot(document.getElementById('app-container') as HTMLElement).render()
diff --git a/src/services/index.ts b/src/services/index.ts
index 1e75a91..afff102 100644
--- a/src/services/index.ts
+++ b/src/services/index.ts
@@ -1,75 +1,75 @@
-import { captureException } from '@sentry/react';
-import axios from 'axios';
-import * as cheerio from 'cheerio';
+import { captureException } from '@sentry/react'
+import axios from 'axios'
+import * as cheerio from 'cheerio'
-import type { Assignment, Video } from '@/types';
+import type { Assignment, Video } from '@/types'
-import { getLinkId } from '@/utils';
+import { getLinkId } from '@/utils'
const fetchDocument = async (url: string) => {
try {
- const response = await axios.get(url);
- const html = response.data;
- const $ = cheerio.load(html);
- return $;
+ const response = await axios.get(url)
+ const html = response.data
+ const $ = cheerio.load(html)
+ return $
} catch (error) {
- console.error(error);
+ console.error(error)
}
-};
+}
/**
* 모든 course를 가져온다.
*/
export const getCourses = async () => {
- const $ = await fetchDocument('https://cyber.gachon.ac.kr/local/ubion/user');
+ const $ = await fetchDocument('https://cyber.gachon.ac.kr/local/ubion/user')
const courses = $('.coursefullname').map((i, el) => {
- const id = getLinkId($(el).attr('href'));
+ const id = getLinkId($(el).attr('href'))
const title = $(el)
.text()
- .replace(/ \((\d{5}_\d{3})\)/, '');
+ .replace(/ \((\d{5}_\d{3})\)/, '')
return {
id,
title,
- };
- });
+ }
+ })
- return courses.get();
-};
+ return courses.get()
+}
/**
* 강의의 activity들을 가져온다.
* @param courseId course id
*/
export const getActivities = async (courseId: string): Promise<(Assignment | Video)[]> => {
- const $ = await fetchDocument(`https://cyber.gachon.ac.kr/course/view.php?id=${courseId}`);
- const assignmentAtCourseDocument = getAssignmentAtCourseDocument($, courseId);
- const videoAtCourseDocument = getVideoAtCourseDocument($, courseId);
+ const $ = await fetchDocument(`https://cyber.gachon.ac.kr/course/view.php?id=${courseId}`)
+ const assignmentAtCourseDocument = getAssignmentAtCourseDocument($, courseId)
+ const videoAtCourseDocument = getVideoAtCourseDocument($, courseId)
- const assignmentSubmittedArray = await getAssignmentSubmitted(courseId);
- const videoSubmittedArray = await getVideoSubmitted(courseId);
+ const assignmentSubmittedArray = await getAssignmentSubmitted(courseId)
+ const videoSubmittedArray = await getVideoSubmitted(courseId)
const assignment = assignmentAtCourseDocument.reduce((acc, cur) => {
const findAssignment = assignmentSubmittedArray.find(
a => a.sectionTitle === cur.sectionTitle && a.title === cur.title,
- );
- if (findAssignment) return [...acc, Object.assign({}, cur, findAssignment)];
+ )
+ if (findAssignment) return [...acc, Object.assign({}, cur, findAssignment)]
- return acc;
- }, []);
+ return acc
+ }, [])
const video = videoAtCourseDocument.reduce((acc, cur) => {
const findVideo = videoSubmittedArray.find(
v => v.sectionTitle === cur.sectionTitle && v.title === cur.title,
- );
- if (findVideo) return [...acc, Object.assign({}, cur, findVideo)];
+ )
+ if (findVideo) return [...acc, Object.assign({}, cur, findVideo)]
- return acc;
- }, []);
+ return acc
+ }, [])
- return [...assignment, ...video];
-};
+ return [...assignment, ...video]
+}
/**
* 강의 페이지의 document에서 과제를 가져온다.
@@ -78,10 +78,10 @@ export const getActivities = async (courseId: string): Promise<(Assignment | Vid
*/
const getAssignmentAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string) => {
const sectionOne = $('#section-0 .modtype_assign .activityinstance').map((i, el) => {
- const link = $(el).find('a').attr('href');
+ const link = $(el).find('a').attr('href')
- const id = getLinkId(link);
- const title = $(el).find('.instancename').clone().children().remove().end().text().trim();
+ const id = getLinkId(link)
+ const title = $(el).find('.instancename').clone().children().remove().end().text().trim()
const assignment = {
type: 'assignment',
@@ -91,26 +91,26 @@ const getAssignmentAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string)
sectionTitle: '',
startAt: '',
endAt: '',
- };
+ }
- return assignment;
- });
+ return assignment
+ })
const sectionTwo = $('.total_sections .content').map((i, el) => {
- const sectionTitle = $(el).find('.sectionname').text().trim();
+ const sectionTitle = $(el).find('.sectionname').text().trim()
return $(el)
.find('.modtype_assign .activityinstance')
.map((i, el) => {
- const link = $(el).find('a').attr('href'); // 링크 없는 과제도 존재
+ const link = $(el).find('a').attr('href') // 링크 없는 과제도 존재
- const id = getLinkId(link);
- const title = $(el).find('.instancename').clone().children().remove().end().text().trim();
+ const id = getLinkId(link)
+ const title = $(el).find('.instancename').clone().children().remove().end().text().trim()
const [startAt, endAt] = $(el)
.find('.displayoptions')
.text()
.split(' ~ ')
- .map(t => t.trim());
+ .map(t => t.trim())
return {
type: 'assignment',
@@ -120,13 +120,13 @@ const getAssignmentAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string)
sectionTitle,
startAt,
endAt,
- };
+ }
})
- .get();
- });
+ .get()
+ })
- return [...sectionOne.get(), ...sectionTwo.get()];
-};
+ return [...sectionOne.get(), ...sectionTwo.get()]
+}
/**
* 강의 페이지의 document에서 동영상 과제를 가져온다.
@@ -136,14 +136,14 @@ const getAssignmentAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string)
const getVideoAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string) => {
return $('.total_sections .content')
.map((i, el) => {
- const sectionTitle = $(el).find('.sectionname').text().trim();
+ const sectionTitle = $(el).find('.sectionname').text().trim()
return $(el)
.find('.activity.vod .activityinstance')
.map((i, el) => {
- const link = $(el).find('a').attr('href'); // 링크 없는 과제도 존재
- const id = getLinkId(link);
- const title = $(el).find('.instancename').clone().children().remove().end().text().trim();
+ const link = $(el).find('a').attr('href') // 링크 없는 과제도 존재
+ const id = getLinkId(link)
+ const title = $(el).find('.instancename').clone().children().remove().end().text().trim()
const [startAt, endAt] = $(el)
.find('.displayoptions .text-ubstrap')
.clone()
@@ -152,13 +152,13 @@ const getVideoAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string) => {
.end()
.text()
.split(' ~ ')
- .map(t => t.trim());
- const timeInfo = $(el).find('.displayoptions .time-info').text();
+ .map(t => t.trim())
+ const timeInfo = $(el).find('.displayoptions .time-info').text()
if (!id) {
captureException(
new Error(`getVideoAtCourseDocument에서 id 없음. ${title} / ${startAt} / ${endAt}`),
- );
+ )
}
return {
@@ -170,41 +170,41 @@ const getVideoAtCourseDocument = ($: cheerio.CheerioAPI, courseId: string) => {
endAt,
timeInfo,
sectionTitle,
- };
+ }
})
- .get();
+ .get()
})
- .get();
-};
+ .get()
+}
/**
* 강의의 과제 제출 여부를 가져온다.
* @param courseId course id
*/
const getAssignmentSubmitted = async (courseId: string) => {
- const $ = await fetchDocument(`https://cyber.gachon.ac.kr/mod/assign/index.php?id=${courseId}`);
+ const $ = await fetchDocument(`https://cyber.gachon.ac.kr/mod/assign/index.php?id=${courseId}`)
- let currentSectionTitle = '';
+ let currentSectionTitle = ''
return $('tbody tr')
.map((i, el) => {
- if ($(el).find('.tabledivider').length) return;
+ if ($(el).find('.tabledivider').length) return
- const sectionTitle = $(el).find('.c0').text().trim();
- if (sectionTitle !== '') currentSectionTitle = sectionTitle;
+ const sectionTitle = $(el).find('.c0').text().trim()
+ if (sectionTitle !== '') currentSectionTitle = sectionTitle
- const title = $(el).find('.c1 a').text().trim();
- const endAt = $(el).find('.c2').text().trim() + ':00';
- const hasSubmitted = /(Submitted for grading)|(제출 완료)/.test($(el).find('.c3').text());
+ const title = $(el).find('.c1 a').text().trim()
+ const endAt = $(el).find('.c2').text().trim() + ':00'
+ const hasSubmitted = /(Submitted for grading)|(제출 완료)/.test($(el).find('.c3').text())
return {
title,
sectionTitle: currentSectionTitle,
endAt,
hasSubmitted,
- };
+ }
})
- .get();
-};
+ .get()
+}
/**
* 강의의 비디오 제출 여부를 가져온다.
@@ -213,31 +213,31 @@ const getAssignmentSubmitted = async (courseId: string) => {
const getVideoSubmitted = async (courseId: string) => {
const $ = await fetchDocument(
`https://cyber.gachon.ac.kr/report/ubcompletion/progress.php?id=${courseId}`,
- );
+ )
const className =
$('.user_progress tbody tr').length === 0
? '.user_progress_table tbody tr'
- : '.user_progress tbody tr';
+ : '.user_progress tbody tr'
- let currentSectionTitle = '';
+ let currentSectionTitle = ''
return $(className)
.map((i, el) => {
if ($(el).find('.sectiontitle').length)
- currentSectionTitle = $(el).find('.sectiontitle').attr('title');
- const std = $(el).find('.text-center.hidden-xs.hidden-sm');
- const title = std.prev().text().trim();
- const requiredTime = std.text().trim();
- const totalStudyTime = std.next().clone().children().remove().end().text().trim();
+ currentSectionTitle = $(el).find('.sectiontitle').attr('title')
+ const std = $(el).find('.text-center.hidden-xs.hidden-sm')
+ const title = std.prev().text().trim()
+ const requiredTime = std.text().trim()
+ const totalStudyTime = std.next().clone().children().remove().end().text().trim()
const hasSubmitted =
- Number(requiredTime.replace(/:/g, '')) <= Number(totalStudyTime.replace(/:/g, ''));
+ Number(requiredTime.replace(/:/g, '')) <= Number(totalStudyTime.replace(/:/g, ''))
return {
title,
hasSubmitted,
sectionTitle: currentSectionTitle,
- };
+ }
})
- .get();
-};
+ .get()
+}
diff --git a/src/types/index.ts b/src/types/index.ts
index 7decc4c..345004e 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,24 +1,24 @@
interface Activity {
- id: string;
- courseId: string;
- title: string;
- sectionTitle: string;
- startAt: string; // 시작 날짜 없는 과제도 존재 ex) No time limit
- endAt: string; // 마감 날짜 없는 과제가 있나? 확실하지 않음
- hasSubmitted: boolean;
+ id: string
+ courseId: string
+ title: string
+ sectionTitle: string
+ startAt: string // 시작 날짜 없는 과제도 존재 ex) No time limit
+ endAt: string // 마감 날짜 없는 과제가 있나? 확실하지 않음
+ hasSubmitted: boolean
}
export interface Course {
- id: string;
- title: string;
+ id: string
+ title: string
}
export interface Assignment extends Activity {
- type: 'assignment';
+ type: 'assignment'
}
export interface Video extends Activity {
- type: 'video';
- timeInfo: string;
+ type: 'video'
+ timeInfo: string
}
-export type ActivityType = Assignment | Video;
+export type ActivityType = Assignment | Video
diff --git a/src/utils/allProgress.ts b/src/utils/allProgress.ts
index ed346dd..c4f4fa7 100644
--- a/src/utils/allProgress.ts
+++ b/src/utils/allProgress.ts
@@ -2,13 +2,13 @@ export default function allProgress(
promise: Promise[],
callback: (progress: number) => void,
) {
- let d = 0;
- callback(0);
+ let d = 0
+ callback(0)
for (const p of promise) {
p.then(() => {
- d++;
- callback((d * 100) / promise.length);
- });
+ d++
+ callback((d * 100) / promise.length)
+ })
}
- return Promise.all(promise);
+ return Promise.all(promise)
}
diff --git a/src/utils/convertDateTime.ts b/src/utils/convertDateTime.ts
index 1fd9937..e19422d 100644
--- a/src/utils/convertDateTime.ts
+++ b/src/utils/convertDateTime.ts
@@ -1,8 +1,8 @@
export default function convertDateTime(dateTime: string) {
- if (!dateTime) return '';
- const [, month, day, hour, minute] = dateTime.split(/\-|:| /);
- const date = new Date(dateTime);
- const dayName = ['일', '월', '화', '수', '목', '금', '토'][date.getDay()];
+ if (!dateTime) return ''
+ const [, month, day, hour, minute] = dateTime.split(/\-|:| /)
+ const date = new Date(dateTime)
+ const dayName = ['일', '월', '화', '수', '목', '금', '토'][date.getDay()]
- return `${month}월 ${day}일 (${dayName}) ${hour}시 ${minute}분`;
+ return `${month}월 ${day}일 (${dayName}) ${hour}시 ${minute}분`
}
diff --git a/src/utils/filteredActivityList.ts b/src/utils/filteredActivityList.ts
index a4bec2c..98f0c75 100644
--- a/src/utils/filteredActivityList.ts
+++ b/src/utils/filteredActivityList.ts
@@ -1,35 +1,35 @@
-import type { ActivityType } from '@/types';
+import type { ActivityType } from '@/types'
-import { pipe } from '@/utils';
+import { pipe } from '@/utils'
const activityListByCourse = (activityList: ActivityType[], id: string) => {
if (id === '-1') {
- return activityList;
+ return activityList
}
- return activityList.filter(activity => activity.courseId === id);
-};
+ return activityList.filter(activity => activity.courseId === id)
+}
const sortAcitivityList = (activityList: ActivityType[]) => {
- return activityList.sort((a, b) => new Date(a.endAt).getTime() - new Date(b.endAt).getTime());
-};
+ return activityList.sort((a, b) => new Date(a.endAt).getTime() - new Date(b.endAt).getTime())
+}
const activityListByStatus = (activityList: ActivityType[], status: string) => {
if (status === '진행중인 과제') {
return activityList.filter(
activity => new Date(activity.endAt).getTime() > new Date().getTime(),
- );
+ )
}
- return activityList;
-};
+ return activityList
+}
const activityListBySubmitted = (activityList: ActivityType[], isChecked: boolean) => {
if (isChecked) {
- return activityList.filter(activity => !activity.hasSubmitted);
+ return activityList.filter(activity => !activity.hasSubmitted)
}
- return activityList;
-};
+ return activityList
+}
const filteredActivities = (
activityList: ActivityType[],
@@ -43,6 +43,6 @@ const filteredActivities = (
activityList => sortAcitivityList(activityList),
activityList => activityListByStatus(activityList, status),
activityList => activityListBySubmitted(activityList, isChecked),
- );
+ )
-export default filteredActivities;
+export default filteredActivities
diff --git a/src/utils/getLinkId.ts b/src/utils/getLinkId.ts
index a3a8c8e..7c09442 100644
--- a/src/utils/getLinkId.ts
+++ b/src/utils/getLinkId.ts
@@ -1,4 +1,4 @@
export default function getLinkId(link: string) {
- if (!link) return '';
- return new URL(link).searchParams.get('id');
+ if (!link) return ''
+ return new URL(link).searchParams.get('id')
}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 6299365..7424606 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,6 +1,6 @@
-export { default as pipe } from './pipe';
-export { default as allProgress } from './allProgress';
-export { default as timeFormat } from './timeFormat';
-export { default as getLinkId } from './getLinkId';
-export { default as convertDateTime } from './convertDateTime';
-export { default as filteredActivityList } from './filteredActivityList';
+export { default as pipe } from './pipe'
+export { default as allProgress } from './allProgress'
+export { default as timeFormat } from './timeFormat'
+export { default as getLinkId } from './getLinkId'
+export { default as convertDateTime } from './convertDateTime'
+export { default as filteredActivityList } from './filteredActivityList'
diff --git a/src/utils/pipe.ts b/src/utils/pipe.ts
index fa69dd9..b884930 100644
--- a/src/utils/pipe.ts
+++ b/src/utils/pipe.ts
@@ -1,7 +1,7 @@
export default function pipe(value: T, ...funcs: ((value: T) => T)[]) {
- let acc = value;
+ let acc = value
for (const f of funcs) {
- acc = f(acc);
+ acc = f(acc)
}
- return acc;
+ return acc
}
diff --git a/src/utils/timeFormat.ts b/src/utils/timeFormat.ts
index 958ce1e..32a88c0 100644
--- a/src/utils/timeFormat.ts
+++ b/src/utils/timeFormat.ts
@@ -1,10 +1,10 @@
export default function timeFormat(endAt: string) {
- if (!endAt) return '';
+ if (!endAt) return ''
- const curDate = new Date();
- const dueDate = new Date(endAt);
- const timeDiff = dueDate.getTime() - curDate.getTime();
- const day = Math.floor(Math.abs(timeDiff) / (1000 * 60 * 60 * 24));
- if ((timeDiff > 0 && day === 0) || timeDiff === 0) return 'D-day';
- return timeDiff < 0 ? '제출마감' : `D-${day}`;
+ const curDate = new Date()
+ const dueDate = new Date(endAt)
+ const timeDiff = dueDate.getTime() - curDate.getTime()
+ const day = Math.floor(Math.abs(timeDiff) / (1000 * 60 * 60 * 24))
+ if ((timeDiff > 0 && day === 0) || timeDiff === 0) return 'D-day'
+ return timeDiff < 0 ? '제출마감' : `D-${day}`
}