File "ElectiveSubjectsModal.tsx"

Full Path: /home/trinadezambia/public_html/student_panel/src/components/ui/pages/dashboard/ElectiveSubjectsModal.tsx
File size: 8.48 KB
MIME-type: text/x-java
Charset: utf-8

'use client';

import { useState, useEffect } from 'react';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from '@/components/ui/dialog';
import { ElectiveSubjectGroup } from '@/lib/api/student/functions';
import Image from 'next/image';
import { BiX } from 'react-icons/bi';
import { useTranslate } from '@/components/hooks/useTranslate';

interface ElectiveSubjectsModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  electiveSubjectGroups: ElectiveSubjectGroup[];
  onSave: (selectedSubjects: { [groupId: number]: number[] }) => void;
}

export default function ElectiveSubjectsModal({
  open,
  onOpenChange,
  electiveSubjectGroups,
  onSave,
}: ElectiveSubjectsModalProps) {
  const translate = useTranslate();
  // State to track selected subjects for each group
  const [selectedSubjects, setSelectedSubjects] = useState<{
    [groupId: number]: number[];
  }>({});

  // Initialize selected subjects state when modal opens
  useEffect(() => {
    if (open) {
      const initialSelection: { [groupId: number]: number[] } = {};
      electiveSubjectGroups.forEach((group) => {
        initialSelection[group.id] = [];
      });
      setSelectedSubjects(initialSelection);
    }
  }, [open, electiveSubjectGroups]);

  // Handle subject selection/deselection
  const handleSubjectToggle = (groupId: number, classSubjectId: number) => {
    setSelectedSubjects((prev) => {
      const currentSelection = prev[groupId] || [];
      const maxSelectable =
        electiveSubjectGroups.find((g) => g.id === groupId)
          ?.total_selectable_subjects || 0;

      // If subject is already selected, remove it
      if (currentSelection.includes(classSubjectId)) {
        return {
          ...prev,
          [groupId]: currentSelection.filter((id) => id !== classSubjectId),
        };
      }

      // If subject is not selected and we haven't reached the limit, add it
      if (currentSelection.length < maxSelectable) {
        return {
          ...prev,
          [groupId]: [...currentSelection, classSubjectId],
        };
      }

      return prev;
    });
  };

  // Handle save button click
  const handleSave = () => {
    onSave(selectedSubjects);
    onOpenChange(false);
  };

  // Check if all groups have valid selections
  const isSelectionValid = () => {
    return electiveSubjectGroups.every((group) => {
      const selected = selectedSubjects[group.id] || [];
      return selected.length === group.total_selectable_subjects;
    });
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent
        className="max-w-[calc(100vw-2rem)] sm:max-w-[600px] p-0 max-h-[90vh] flex flex-col"
        showCloseButton={false}
      >
        {/* Header */}
        <DialogHeader className="p-3 pb-2 sm:p-6 sm:pb-4 border-b border-gray-200 flex-shrink-0">
          <div className="flex items-start justify-between text-left">
            <div className="flex-1 pr-2">
              <DialogTitle className="text-base sm:text-xl font-bold text-gray-900 mb-1 sm:mb-2">
                {translate('chooseYourElectiveSubjects')}
              </DialogTitle>
              <DialogDescription className="text-xs sm:text-sm font-normal text-gray-600 leading-relaxed">
                {translate('selectElectiveSubjectsDescription')}
              </DialogDescription>
            </div>
            <DialogClose asChild>
              <button className="ml-2 sm:ml-4 p-1.5 sm:p-2 bg-[var(--light-primary-color)] rounded-[4px] transition-colors border border-gray-200 flex-shrink-0">
                <BiX className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
              </button>
            </DialogClose>
          </div>
        </DialogHeader>

        {/* Content - Scrollable area */}
        <div className="flex-1 overflow-y-auto px-3 py-3 sm:px-6 sm:py-4 space-y-4 sm:space-y-6">
          {electiveSubjectGroups.map((group, groupIndex) => (
            <div
              key={group.id}
              className="space-y-3 bg-[var(--light-primary-color)] border border-gray-200 rounded-lg p-3 sm:p-4"
            >
              {/* Group Header */}
              <div className="bg-[var(--light-primary-color)] rounded-lg">
                <h3 className="text-base font-normal text-gray-900">
                  {translate('group')} {groupIndex + 1}{' '}
                  <span className="text-sm font-normal text-gray-700">
                    ({translate('selectAny')} {group.total_selectable_subjects}{' '}
                    {translate('subjects')})
                  </span>
                </h3>
              </div>

              {/* Subjects Grid */}
              <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
                {group.subjects.map((subject) => {
                  const isSelected =
                    selectedSubjects[group.id]?.includes(
                      subject.class_subject_id
                    ) || false;
                  const canSelect =
                    isSelected ||
                    (selectedSubjects[group.id]?.length || 0) <
                      group.total_selectable_subjects;

                  return (
                    <div
                      key={subject.id}
                      className={`bg-white border border-gray-200 rounded-lg p-3 sm:p-4 cursor-pointer transition-all ${
                        isSelected
                          ? 'ring-2 ring-[var(--primary-color)] bg-(--primary-color)'
                          : canSelect
                          ? 'hover:bg-gray-200'
                          : 'opacity-50 cursor-not-allowed'
                      }`}
                      onClick={() =>
                        canSelect &&
                        handleSubjectToggle(group.id, subject.class_subject_id)
                      }
                    >
                      <div className="flex items-center space-x-2 sm:space-x-3">
                        {/* Subject Image */}
                        <div className="w-6 h-6 sm:w-8 sm:h-8 rounded overflow-hidden flex-shrink-0">
                          <Image
                            src={subject.image}
                            alt={subject.name}
                            className="w-full h-full object-cover"
                            width={0}
                            height={0}
                          />
                        </div>

                        {/* Subject Info */}
                        <div className="flex-1 min-w-0">
                          <h4 className="text-sm sm:text-base font-medium text-gray-900 line-clamp-2">
                            {subject.name_with_type}
                          </h4>
                        </div>

                        {/* Selection Checkbox */}
                        <div
                          className={`w-5 h-5 rounded border-2 flex items-center justify-center ${
                            isSelected
                              ? 'bg-(--primary-color) border-[var(--primary-color)]'
                              : 'border-gray-300 bg-white'
                          }`}
                        >
                          {isSelected && (
                            <svg
                              className="w-3 h-3 text-white"
                              fill="currentColor"
                              viewBox="0 0 20 20"
                            >
                              <path
                                fillRule="evenodd"
                                d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
                                clipRule="evenodd"
                              />
                            </svg>
                          )}
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
        </div>

        {/* Footer */}
        <div className="p-3 pt-2 sm:p-6 sm:pt-4 border-t border-gray-200 flex-shrink-0">
          <button
            onClick={handleSave}
            disabled={!isSelectionValid()}
            className={`w-full py-2.5 sm:py-3 rounded-lg font-bold text-white transition-colors text-sm sm:text-base ${
              isSelectionValid()
                ? 'bg-(--primary-color) hover:bg-(--primary-color)/90'
                : 'bg-gray-300 cursor-not-allowed'
            }`}
          >
            {translate('addSelectiveSubjects')}
          </button>
        </div>
      </DialogContent>
    </Dialog>
  );
}