Skip to content

Commit

Permalink
Merge pull request #4 from whats2000/main
Browse files Browse the repository at this point in the history
Add: Add click to scroll index
  • Loading branch information
whats2000 authored Nov 25, 2024
2 parents 85d4f8f + ce967ca commit b2d96f6
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 15 deletions.
14 changes: 14 additions & 0 deletions client-website/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ interface AppState {
selectedSemester: string;
availableSemesters: AcademicYear;
};
clickedCourseId?: string | null;
}

class App extends Component<{}, AppState> {
Expand All @@ -101,6 +102,7 @@ class App extends Component<{}, AppState> {
history: {},
},
},
clickedCourseId: null,
};

componentDidMount() {
Expand Down Expand Up @@ -415,6 +417,15 @@ class App extends Component<{}, AppState> {
this.setState({ loading: null });
};

// whats2000: 新增處理課程點擊事件
/**
* 處理課程點擊
* @param course {Course} 課程資料
*/
onCourseClick = (course: Course) => {
this.setState({ clickedCourseId: course.Number });
};

/**
* 渲染元件
* @returns {React.ReactNode} 元件
Expand All @@ -431,6 +442,7 @@ class App extends Component<{}, AppState> {
availableCourseHistoryData,
loading,
searchTimeSlot,
clickedCourseId,
} = this.state;
const slideStyle = {
marginLeft: isCollapsed ? (window.innerWidth >= 992 ? '-50%' : '0') : '0',
Expand Down Expand Up @@ -480,6 +492,7 @@ class App extends Component<{}, AppState> {
onCourseHover={this.handleCourseHover}
searchTimeSlot={searchTimeSlot}
toggleSearchTimeSlot={this.toggleSearchTimeSlot}
onCourseClick={this.onCourseClick}
/>
</SlideColContainer>

Expand All @@ -499,6 +512,7 @@ class App extends Component<{}, AppState> {
latestCourseHistoryData={latestCourseHistoryData}
convertVersion={this.convertVersion}
searchTimeSlot={searchTimeSlot}
clickedCourseId={clickedCourseId}
/>
</FixedHeightCol>
</Row>
Expand Down
28 changes: 15 additions & 13 deletions client-website/src/components/ScheduleTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component } from 'react';
import styled from 'styled-components';
import styled, { css } from 'styled-components';

import type { Course, TimeSlot, Weekday } from '@/types';
import CourseBlock from './ScheduleTable/CourseBlock';
Expand All @@ -21,23 +21,20 @@ const StyledTable = styled.table`
const HeaderCell = styled.th`
font-weight: normal;
padding: 2px !important;
// background-color: lightgray !important;
opacity: 1;
!important;
opacity: 1 !important;
`;

const TimeSlotCell = styled.th`
width: 4%;
padding: 2px !important;
font-weight: normal;
// background-color: lightgray !important;
opacity: 1;
!important;
opacity: 1 !important;
`;

// Cellery: 更改選取樣式
const SelectedTimeSlot = `
const SelectedTimeSlot = css`
background-color: #e1e39f !important;
opacity: 1 !important;
`;

const CourseCell = styled.td`
Expand All @@ -64,6 +61,7 @@ interface ScheduleTableProps {
onCourseHover: (courseId: string | null) => void;
searchTimeSlot: TimeSlot[];
toggleSearchTimeSlot: (timeSlot: TimeSlot) => void;
onCourseClick: (course: Course) => void; // New prop for handling course click
}

class ScheduleTable extends Component<ScheduleTableProps> {
Expand All @@ -81,9 +79,7 @@ class ScheduleTable extends Component<ScheduleTableProps> {
[key: string]: Course[];
} => {
const { selectedCourses } = this.props;
const coursesTable: {
[key: string]: Course[];
} = {};
const coursesTable: { [key: string]: Course[] } = {};

this.setting.timeSlots.forEach((timeSlot) => {
this.setting.weekday.forEach((weekday) => {
Expand Down Expand Up @@ -130,8 +126,13 @@ class ScheduleTable extends Component<ScheduleTableProps> {
};

render() {
const { hoveredCourseId, onCourseHover, handleCourseSelect, currentTab } =
this.props;
const {
hoveredCourseId,
onCourseHover,
handleCourseSelect,
currentTab,
onCourseClick,
} = this.props;
const coursesTable = this.createCourseTable();

const isAtCourseDetectiveTab = currentTab === '課程偵探';
Expand Down Expand Up @@ -196,6 +197,7 @@ class ScheduleTable extends Component<ScheduleTableProps> {
handleCourseSelect={handleCourseSelect}
hoveredCourseId={hoveredCourseId}
onCourseHover={onCourseHover}
onCourseClick={onCourseClick}
/>
),
)}
Expand Down
13 changes: 13 additions & 0 deletions client-website/src/components/ScheduleTable/CourseBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const StyledCourseBlock = styled.div`
padding: 2px 4px;
font-size: 9px;
text-align: center;
cursor: pointer;
&:last-child {
margin-bottom: 0;
Expand All @@ -51,6 +52,7 @@ interface CourseBlockProps {
onCourseHover: (courseId: string | null) => void;
hoveredCourseId: string | null;
handleCourseSelect: (course: Course, isSelected: boolean) => void;
onCourseClick?: (course: Course) => void; // New optional prop
}

class CourseBlock extends Component<CourseBlockProps> {
Expand All @@ -62,6 +64,16 @@ class CourseBlock extends Component<CourseBlockProps> {
handleCourseSelect(course, false); // 調用父組件的函數來刪除課程
};

/**
* 處理課程點擊事件
*/
handleCourseClick = () => {
const { onCourseClick, course } = this.props;
if (onCourseClick) {
onCourseClick(course);
}
};

/**
* 產生一個顏色,並且保持其亮度
* @param courseUniqueCode {string} 課程唯一代碼
Expand Down Expand Up @@ -104,6 +116,7 @@ class CourseBlock extends Component<CourseBlockProps> {
onMouseEnter={() => onCourseHover(course['Number'])}
onMouseLeave={() => onCourseHover(null)}
style={courseBlockStyle}
onClick={this.handleCourseClick}
>
<span className='d-block fw-bold'>{course['Name']}</span>
{course['Room'].split('\n').map((room, index) => (
Expand Down
5 changes: 5 additions & 0 deletions client-website/src/components/SelectorSetting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface SelectorSettingProps {
latestCourseHistoryData: string;
convertVersion: (version: string) => string | React.ReactNode;
searchTimeSlot: TimeSlot[];
clickedCourseId: string | null;
}

interface SelectorSettingState {
Expand Down Expand Up @@ -146,6 +147,7 @@ class SelectorSetting extends Component<
latestCourseHistoryData,
convertVersion,
searchTimeSlot,
clickedCourseId,
} = this.props;
const { filterOptions } = this.state;

Expand All @@ -162,6 +164,7 @@ class SelectorSetting extends Component<
filterOptions={filterOptions}
detectTimeConflict={this.detectTimeConflict}
calculateTotalCreditsAndHours={this.calculateTotalCreditsAndHours}
clickedCourseId={clickedCourseId}
/>
),
學期必修: (
Expand All @@ -175,6 +178,7 @@ class SelectorSetting extends Component<
filterOptions={filterOptions}
detectTimeConflict={this.detectTimeConflict}
calculateTotalCreditsAndHours={this.calculateTotalCreditsAndHours}
clickedCourseId={clickedCourseId}
/>
),
課程偵探: (
Expand All @@ -188,6 +192,7 @@ class SelectorSetting extends Component<
searchTimeSlot={searchTimeSlot}
detectTimeConflict={this.detectTimeConflict}
calculateTotalCreditsAndHours={this.calculateTotalCreditsAndHours}
clickedCourseId={clickedCourseId}
/>
),
已選匯出: (
Expand Down
3 changes: 3 additions & 0 deletions client-website/src/components/SelectorSetting/AllCourse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface AllCourseProps {
totalCredits: number;
totalHours: number;
};
clickedCourseId: string | null;
}

interface AllCourseState {
Expand Down Expand Up @@ -359,6 +360,7 @@ class AllCourse extends Component<AllCourseProps, AllCourseState> {
isCollapsed,
detectTimeConflict,
calculateTotalCreditsAndHours,
clickedCourseId,
} = this.props;
const {
filteredCourses,
Expand Down Expand Up @@ -408,6 +410,7 @@ class AllCourse extends Component<AllCourseProps, AllCourseState> {
displaySelectedOnly={displaySelectedOnly}
onCourseSelect={onCourseSelect}
onCourseHover={onCourseHover}
clickedCourseId={clickedCourseId}
/>
</StyledCardBody>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
import React, { Component, createRef } from 'react';
import { Card } from 'react-bootstrap';
import { Virtuoso } from 'react-virtuoso';
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';

import type { Course } from '@/types';
import Header from './AllCourseList/Header';
Expand All @@ -16,9 +16,26 @@ interface CoursesListProps {
onCourseSelect: (course: Course, isSelected: boolean) => void;
onCourseHover: (courseId: string | null) => void;
hoveredCourseId: string | null;
clickedCourseId: string | null;
}

class CoursesList extends Component<CoursesListProps> {
private virtuosoRef = createRef<VirtuosoHandle>();

componentDidUpdate(prevProps: Readonly<CoursesListProps>) {
if (
prevProps.clickedCourseId !== this.props.clickedCourseId &&
this.props.clickedCourseId
) {
const course = this.props.courses.find(
(c) => c['Number'] === this.props.clickedCourseId,
);
if (course) {
this.scrollToCourse(course);
}
}
}

/**
* 渲染列表項目
* @param {number} index
Expand Down Expand Up @@ -75,6 +92,22 @@ class CoursesList extends Component<CoursesListProps> {
);
};

/**
* 滾動到特定課程
* @param {Course} course - 要滾動到的課程
*/
scrollToCourse = (course: Course) => {
if (this.virtuosoRef.current) {
const courseIndex = this.props.courses.findIndex(
(c) => c['Number'] === course['Number'],
);
if (courseIndex !== -1) {
// Add 1 to account for the header
this.virtuosoRef.current.scrollToIndex(courseIndex + 1);
}
}
};

render() {
const { courses } = this.props;

Expand All @@ -93,6 +126,7 @@ class CoursesList extends Component<CoursesListProps> {

return (
<Virtuoso
ref={this.virtuosoRef}
data={dataWithHeader}
itemContent={this.renderItem}
topItemCount={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ interface CourseDetectiveProps {
hoveredCourseId: string | null;
onCourseSelect: (course: Course, isSelected: boolean) => void;
onCourseHover: (courseId: string | null) => void;
clickedCourseId: string | null;
}

interface CourseDetectiveState {
Expand Down Expand Up @@ -222,6 +223,7 @@ class CourseDetective extends Component<
hoveredCourseId,
onCourseSelect,
onCourseHover,
clickedCourseId,
} = this.props;
const { orderElements, filteredCourses } = this.state;
return (
Expand Down Expand Up @@ -257,6 +259,7 @@ class CourseDetective extends Component<
onCourseSelect={onCourseSelect}
onCourseHover={onCourseHover}
displaySelectedOnly={false}
clickedCourseId={clickedCourseId}
/>
</StyledCardBody>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ interface RequiredCourseProps {
totalHours: number;
};
filterOptions: typeof DEFAULT_FILTER_OPTIONS;
clickedCourseId: string | null;
}

interface RequiredCourseState {
Expand Down Expand Up @@ -118,6 +119,7 @@ class RequiredCourse extends Component<
detectTimeConflict,
calculateTotalCreditsAndHours,
filterOptions,
clickedCourseId,
} = this.props;
const { requiredCourseFilters, filteredCourses } = this.state;

Expand Down Expand Up @@ -152,6 +154,7 @@ class RequiredCourse extends Component<
onCourseSelect={onCourseSelect}
onCourseHover={onCourseHover}
displaySelectedOnly={false}
clickedCourseId={clickedCourseId}
/>
</StyledCardBody>
</Card>
Expand Down

0 comments on commit b2d96f6

Please sign in to comment.