getSyllabus method

Future<SyllabusDto> getSyllabus({
  1. required String courseNumber,
  2. required String syllabusId,
})

Fetches the detailed syllabus for a course offering.

Returns syllabus information including course objectives, textbooks, grading policy, and weekly plan.

The courseNumber should be a course offering number (e.g., "346774"), and syllabusId should be obtained from the syllabusId field of a ScheduleDto.

Throws an Exception if the syllabus tables are not found.

Implementation

Future<SyllabusDto> getSyllabus({
  required String courseNumber,
  required String syllabusId,
}) async {
  final response = await _courseDio.get(
    'ShowSyllabus.jsp',
    queryParameters: {'snum': courseNumber, 'code': syllabusId},
  );

  final document = parse(response.data);
  final tables = document.querySelectorAll('table');
  if (tables.length < 2) {
    throw Exception('Syllabus tables not found.');
  }

  // Table 0: Header table (課程基本資料)
  // Row 1 contains: semester, number, name, phase, credits, hours, type,
  // instructor, classes, enrolled, withdrawn, remarks
  final headerRow = tables[0].querySelectorAll('tr')[1];
  final headerCells = headerRow.querySelectorAll('td');

  final typeSymbol = _parseCellText(headerCells[6]);
  final type = CourseType.values.firstWhereOrNull(
    (t) => t.symbol == typeSymbol,
  );
  final enrolled = int.tryParse(headerCells[9].text.trim());
  final withdrawn = int.tryParse(headerCells[10].text.trim());

  // Table 1: Syllabus table (教學大綱與進度)
  // Rows 0-2: Label and value both in th elements
  // Rows 3+: Label in th, value in td (some with textarea)
  final syllabusRows = tables[1].querySelectorAll('tr');

  final email = _parseCellText(syllabusRows[1].querySelectorAll('th')[1]);
  final lastUpdatedText = _parseCellText(
    syllabusRows[2].querySelectorAll('th')[1],
  );
  final lastUpdated = DateTime.tryParse(lastUpdatedText ?? '');

  // Rows 3-5 have textarea elements for long content
  final objective = _parseTextareaValue(syllabusRows[3]);
  final weeklyPlan = _parseTextareaValue(syllabusRows[4]);
  final evaluation = _parseTextareaValue(syllabusRows[5]);
  final materials = _parseTextareaValue(syllabusRows[6]);

  final remarksTd = syllabusRows[10].querySelector('td');
  final remarks = remarksTd != null ? _parseCellText(remarksTd) : null;

  return (
    type: type,
    enrolled: enrolled,
    withdrawn: withdrawn,
    email: email,
    lastUpdated: lastUpdated,
    objective: objective,
    weeklyPlan: weeklyPlan,
    evaluation: evaluation,
    materials: materials,
    remarks: remarks,
  );
}