Skip to content

Commit f82191f

Browse files
Merge pull request #114 from sparcs-kaist/rc
Release v3.4.4
2 parents 2891812 + 80add2d commit f82191f

File tree

7 files changed

+165
-19
lines changed

7 files changed

+165
-19
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"react-slick": "^0.29.0",
4646
"redux": "^4.0.0",
4747
"slick-carousel": "^1.8.1",
48-
"zabo-embed": "^0.0.7"
48+
"zabo-embed": "^0.0.7",
49+
"react-notion": "^0.10.0"
4950
},
5051
"devDependencies": {
5152
"@babel/plugin-proposal-decorators": "^7.24.1",

src/components/sections/dictionary/courselist/CourseListSection.jsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ const REFRESH_LIMIT = 10;
3737
class CourseListSection extends Component {
3838
constructor(props) {
3939
super(props);
40-
this.offSetRef = React.createRef();
41-
}
42-
43-
componentDidMount() {
44-
if (this.offSetRef.current) {
45-
this.offSetRef.current.value = REFRESH_LIMIT;
46-
}
4740
}
4841

4942
onScrollChange = (e) => {

src/components/sections/timetable/lecturelist/LectureListSection.jsx

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
22
import { connect } from 'react-redux';
33
import PropTypes from 'prop-types';
44
import { withTranslation } from 'react-i18next';
5+
import axios from 'axios';
56
import ReactGA from 'react-ga4';
67
import { range } from 'lodash';
78

@@ -21,9 +22,11 @@ import {
2122
deleteLectureFromCart,
2223
setIsLectureListOpenOnMobile,
2324
} from '../../../../redux/actions/timetable/list';
24-
import { openSearch } from '../../../../redux/actions/timetable/search';
25+
import { openSearch, setLastSearchOption } from '../../../../redux/actions/timetable/search';
2526
import { addLectureToTimetable } from '../../../../redux/actions/timetable/timetable';
2627

28+
import { setListLectures } from '../../../../redux/actions/timetable/list';
29+
2730
import { LectureFocusFrom } from '@/shapes/enum';
2831
import { LectureListCode } from '@/shapes/enum';
2932

@@ -59,12 +62,20 @@ import {
5962
import LectureGroupBlockRow from '../../../blocks/LectureGroupBlockRow';
6063
import { TIMETABLE_START_HOUR } from '../../../../common/constants';
6164

65+
const REFRESH_LIMIT = 50;
66+
6267
class LectureListSection extends Component {
6368
constructor(props) {
6469
super(props);
6570
this.arrowRef = React.createRef();
6671
}
6772

73+
onScrollChange = (e) => {
74+
const { scrollTop, scrollHeight, clientHeight } = e;
75+
76+
if (scrollTop + clientHeight >= scrollHeight) this._addLectureGroups();
77+
};
78+
6879
componentDidMount() {
6980
window.addEventListener('resize', this.selectWithArrow);
7081
}
@@ -293,6 +304,64 @@ class LectureListSection extends Component {
293304
return lists[selectedListCode].lectureGroups;
294305
};
295306

307+
_addLectureGroups = async () => {
308+
const {
309+
lastSearchOption,
310+
setLastSearchOption,
311+
year,
312+
semester,
313+
setListLecturesDispatch,
314+
lists,
315+
} = this.props;
316+
317+
const lectures = this._getLectureGroups(LectureListCode.SEARCH, lists);
318+
319+
let offset = 0;
320+
321+
for (let i = 0; i < lectures.length - 1; i++) {
322+
offset += lectures[i].length;
323+
}
324+
325+
const option = {
326+
...lastSearchOption,
327+
offset,
328+
limit: offset + REFRESH_LIMIT,
329+
};
330+
331+
await axios
332+
.get('/api/lectures', {
333+
params: {
334+
year: year,
335+
semester: semester,
336+
...option,
337+
order: ['old_code', 'class_no'],
338+
},
339+
metadata: {
340+
gaCategory: 'Timetable',
341+
gaVariable: 'POST / List',
342+
},
343+
})
344+
.then((response) => {
345+
const newProps = this.props;
346+
if (newProps.year !== year || newProps.semester !== semester) {
347+
return;
348+
}
349+
if (response.data.length > 0) {
350+
const newLectures = lectures;
351+
let spreadedLectures = [];
352+
353+
for (let i = 0; i < newLectures.length - 1; i++) {
354+
spreadedLectures = spreadedLectures.concat(newLectures[i]);
355+
}
356+
357+
spreadedLectures = spreadedLectures.concat(response.data);
358+
359+
setListLecturesDispatch(LectureListCode.SEARCH, spreadedLectures);
360+
}
361+
})
362+
.catch((error) => {});
363+
};
364+
296365
render() {
297366
const { t } = this.props;
298367
const { user, lectureFocus, selectedTimetable, selectedListCode, lastSearchOption, lists } =
@@ -376,7 +445,12 @@ class LectureListSection extends Component {
376445
);
377446
}
378447
return (
379-
<Scroller onScroll={this.selectWithArrow} key={selectedListCode}>
448+
<Scroller
449+
onScroll={(e) => {
450+
this.selectWithArrow();
451+
this.onScrollChange(e);
452+
}}
453+
key={selectedListCode}>
380454
<div className={classNames('block-list')}>
381455
{lectureGroups.map((lg) => (
382456
<LectureGroupBlock
@@ -467,6 +541,12 @@ const mapDispatchToProps = (dispatch) => ({
467541
setIsLectureListOpenOnMobileDispatch: (isLectureListOpenOnMobile) => {
468542
dispatch(setIsLectureListOpenOnMobile(isLectureListOpenOnMobile));
469543
},
544+
setLastSearchOptionDispatch: (lastSearchOption) => {
545+
dispatch(setLastSearchOption(lastSearchOption));
546+
},
547+
setListLecturesDispatch: (code, lectures) => {
548+
dispatch(setListLectures(code, lectures));
549+
},
470550
});
471551

472552
LectureListSection.propTypes = {
@@ -485,8 +565,10 @@ LectureListSection.propTypes = {
485565
clearLectureFocusDispatch: PropTypes.func.isRequired,
486566
addLectureToTimetableDispatch: PropTypes.func.isRequired,
487567
addLectureToCartDispatch: PropTypes.func.isRequired,
568+
setListLecturesDispatch: PropTypes.func.isRequired,
488569
deleteLectureFromCartDispatch: PropTypes.func.isRequired,
489570
setIsLectureListOpenOnMobileDispatch: PropTypes.func.isRequired,
571+
setLastSearchOptionDispatch: PropTypes.func.isRequired,
490572
};
491573

492574
export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(LectureListSection));

src/components/sections/timetable/lecturelist/LectureSearchSubSection.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class LectureSearchSubSection extends Component {
5555
};
5656

5757
searchStart = () => {
58-
const LIMIT = 300;
58+
const LIMIT = 50;
5959

6060
const { t } = this.props;
6161
const { selectedTypes, selectedDepartments, selectedLevels, keyword } = this.state;
@@ -96,6 +96,8 @@ class LectureSearchSubSection extends Component {
9696
day: classtimeDay !== null ? classtimeDay : undefined,
9797
begin: classtimeBegin !== null ? classtimeBegin / 30 - 8 * 2 : undefined,
9898
end: classtimeEnd !== null ? classtimeEnd / 30 - 8 * 2 : undefined,
99+
limit: LIMIT,
100+
offset: 0,
99101
};
100102

101103
this.setState(this.INITIAL_STATE);
@@ -113,7 +115,6 @@ class LectureSearchSubSection extends Component {
113115
semester: semester,
114116
...option,
115117
order: ['old_code', 'class_no'],
116-
limit: LIMIT,
117118
},
118119
metadata: {
119120
gaCategory: 'Timetable',
@@ -125,10 +126,10 @@ class LectureSearchSubSection extends Component {
125126
if (newProps.year !== year || newProps.semester !== semester) {
126127
return;
127128
}
128-
if (response.data.length === LIMIT) {
129-
// eslint-disable-next-line no-alert
130-
alert(t('ui.message.tooManySearchResults', { count: LIMIT }));
131-
}
129+
// if (response.data.length === LIMIT) {
130+
// // eslint-disable-next-line no-alert
131+
// alert(t('ui.message.tooManySearchResults', { count: LIMIT }));
132+
// }
132133
setListLecturesDispatch(LectureListCode.SEARCH, response.data);
133134
})
134135
.catch((error) => {});

src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import ko from '@/translations/translation.ko.json';
3838

3939
import 'slick-carousel/slick/slick.css';
4040
import 'slick-carousel/slick/slick-theme.css';
41+
import UpdatePage from '@/pages/UpdatePage';
4142

4243
declare global {
4344
interface Window {
@@ -177,6 +178,7 @@ const router = createBrowserRouter([
177178
{ path: 'error/:message', element: <ErrorPage /> },
178179
{ path: 'login/success', element: <LoginSuccessHandler /> },
179180
{ path: 'developer-login', element: <DeveloperLoginPage /> },
181+
{ path: 'update', element: <UpdatePage /> },
180182
{ path: '*', element: <Navigate to="/" /> },
181183
],
182184
},

src/pages/UpdatePage.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { NotionRenderer } from 'react-notion';
2+
3+
import { useEffect, useState } from 'react';
4+
5+
import 'react-notion/src/styles.css';
6+
import 'prismjs/themes/prism-tomorrow.css';
7+
import { appBoundClassNames as classNames } from '@/common/boundClassNames';
8+
9+
const DEFAULT_PAGE_ID = '23ac25603b0b80f8b343d2324a7e2131';
10+
const OFFICIAL_SPACE_ID = 'ca8b3bc6-6b17-4a1f-8f57-2dd4b58a84f7';
11+
12+
const UpdatePage = () => {
13+
const [blockMap, setBlockMap] = useState(null);
14+
const query = new URLSearchParams(window.location.search);
15+
const pageId = query.get('pageId') || DEFAULT_PAGE_ID;
16+
const [spaceId, setSpaceId] = useState('');
17+
18+
useEffect(() => {
19+
const fetchNotionData = async () => {
20+
const res = await fetch(`https://notion-api.splitbee.io/v1/page/${pageId}`);
21+
const json = await res.json();
22+
Object.keys(json).forEach((key) => {
23+
if (json[key].role === 'none') {
24+
delete json[key];
25+
} else {
26+
setSpaceId(json[key].value.space_id);
27+
}
28+
});
29+
setBlockMap(json);
30+
};
31+
fetchNotionData();
32+
}, []);
33+
useEffect(() => {
34+
if (spaceId !== '' && spaceId !== OFFICIAL_SPACE_ID) {
35+
window.location.href = '/update';
36+
}
37+
}, [spaceId]);
38+
39+
return (
40+
<section className={classNames('content', 'content--no-scroll')}>
41+
{blockMap !== null && spaceId === OFFICIAL_SPACE_ID && (
42+
<NotionRenderer
43+
blockMap={blockMap}
44+
fullPage={true}
45+
hideHeader={true}
46+
mapPageUrl={(pageId) => {
47+
return '/update?' + new URLSearchParams({ pageId: pageId });
48+
}}
49+
/>
50+
)}
51+
</section>
52+
);
53+
};
54+
55+
export default UpdatePage;

yarn.lock

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4202,7 +4202,7 @@ inflight@^1.0.4:
42024202

42034203
inherits@2:
42044204
version "2.0.4"
4205-
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
4205+
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
42064206
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
42074207

42084208
inline-style-parser@0.1.1:
@@ -5479,7 +5479,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
54795479

54805480
minimist@^1.2.0, minimist@^1.2.6:
54815481
version "1.2.8"
5482-
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
5482+
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
54835483
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
54845484

54855485
moment@^2.29.2:
@@ -5639,7 +5639,7 @@ object.values@^1.1.6:
56395639

56405640
once@^1.3.0:
56415641
version "1.4.0"
5642-
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
5642+
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
56435643
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
56445644
dependencies:
56455645
wrappy "1"
@@ -5923,6 +5923,11 @@ pretty-format@^29.0.0, pretty-format@^29.7.0:
59235923
ansi-styles "^5.0.0"
59245924
react-is "^18.0.0"
59255925

5926+
prismjs@^1.21.0:
5927+
version "1.30.0"
5928+
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9"
5929+
integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==
5930+
59265931
prompts@^2.0.1:
59275932
version "2.4.2"
59285933
resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz"
@@ -6063,6 +6068,13 @@ react-markdown@^7.1.0:
60636068
unist-util-visit "^4.0.0"
60646069
vfile "^5.0.0"
60656070

6071+
react-notion@^0.10.0:
6072+
version "0.10.0"
6073+
resolved "https://registry.yarnpkg.com/react-notion/-/react-notion-0.10.0.tgz#d30876b681b09d91dc671b04c7f604adb4e2499e"
6074+
integrity sha512-i5lVAxzSs7GnTpIbKtivPQWxGZiKCO5xmCmMJyn6F91y8X1IIJqnypkK+31F2acb1l1Qd8Yv0ktuvXwz9g49NQ==
6075+
dependencies:
6076+
prismjs "^1.21.0"
6077+
60666078
react-redux@^7.2.1:
60676079
version "7.2.9"
60686080
resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz"

0 commit comments

Comments
 (0)