Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
/>

{/* Modal */}
<div className="relative bg-white dark:bg-gray-800 rounded-2xl shadow-2xl max-w-md w-full mx-4 overflow-hidden">
<div className="relative bg-white dark:bg-gray-800 rounded-2xl shadow-2xl max-w-sm sm:max-w-md w-full mx-4 max-h-[90vh] overflow-y-auto overflow-hidden">
{/* Close button */}
<button
onClick={onClose}
className="absolute top-4 right-4 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
className="absolute top-4 end-4 p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
aria-label="Close"
>
<HiX className="w-5 h-5 text-gray-500 dark:text-gray-400" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,15 @@ export default function EnrollmentActions({
const { t } = useTranslation();
const [showLeaveModal, setShowLeaveModal] = useState(false);

const { status, role, isLoading, isLastTeacher, enroll, leave, cancelRequest } =
enrollment;
const {
status,
role,
isLoading,
isLastTeacher,
enroll,
leave,
cancelRequest,
} = enrollment;

const handleLeaveConfirm = async () => {
await leave();
Expand All @@ -47,7 +54,7 @@ export default function EnrollmentActions({
<button
onClick={enroll}
disabled={isLoading}
className="inline-flex items-center gap-2 px-6 py-3 bg-green-600 hover:bg-green-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-all shadow-lg hover:shadow-xl disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer"
className="inline-flex items-center justify-center gap-2 px-6 py-3 bg-green-600 hover:bg-green-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-all shadow-lg hover:shadow-xl disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer w-full sm:w-auto"
>
<HiArrowRightOnRectangle className="w-5 h-5" />
{isLoading
Expand All @@ -65,7 +72,7 @@ export default function EnrollmentActions({
<button
onClick={enroll}
disabled={isLoading}
className="inline-flex items-center gap-2 px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-all shadow-lg hover:shadow-xl disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer"
className="inline-flex items-center justify-center gap-2 px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-all shadow-lg hover:shadow-xl disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer w-full sm:w-auto"
>
<HiArrowRightOnRectangle className="w-5 h-5" />
{isLoading
Expand Down Expand Up @@ -124,7 +131,9 @@ export default function EnrollmentActions({
<div className="flex items-center gap-2 flex-1">
<HiEnvelope className="w-5 h-5 text-blue-600 dark:text-blue-400 flex-shrink-0" />
<p className="text-blue-800 dark:text-blue-200 text-sm font-medium">
{t("course.enrollment.invitedBanner", { role: role || "student" })}
{t("course.enrollment.invitedBanner", {
role: role || "student",
})}
</p>
</div>
<div className="flex gap-2">
Expand Down Expand Up @@ -157,7 +166,7 @@ export default function EnrollmentActions({
<button
disabled
title={t("course.enrollment.lastTeacherTooltip")}
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 text-gray-400 dark:text-gray-500 rounded-lg font-medium opacity-50 cursor-not-allowed"
className="inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 text-gray-400 dark:text-gray-500 rounded-lg font-medium opacity-50 cursor-not-allowed w-full sm:w-auto"
>
<HiArrowLeftOnRectangle className="w-5 h-5" />
{t("course.enrollment.leaveButton")}
Expand All @@ -173,7 +182,7 @@ export default function EnrollmentActions({
<button
onClick={() => setShowLeaveModal(true)}
disabled={isLoading}
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 hover:border-red-500 dark:hover:border-red-400 text-gray-700 dark:text-gray-200 hover:text-red-600 dark:hover:text-red-400 rounded-lg font-medium transition-all disabled:opacity-50 cursor-pointer"
className="inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 hover:border-red-500 dark:hover:border-red-400 text-gray-700 dark:text-gray-200 hover:text-red-600 dark:hover:text-red-400 rounded-lg font-medium transition-all disabled:opacity-50 cursor-pointer w-full sm:w-auto"
>
<HiArrowLeftOnRectangle className="w-5 h-5" />
{t("course.enrollment.leaveButton")}
Expand Down
18 changes: 9 additions & 9 deletions Frontend/EduLiteFrontend/src/components/courses/MembersTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ const MembersTab: React.FC<MembersTabProps> = ({
choices={ROLE_CHOICES}
showLabel={false}
disabled={changingRole === member.id}
className="!py-1 !pl-2 !pr-8 text-sm"
className="!py-1 !ps-2 !pe-8 text-sm"
/>
</div>
) : (
Expand Down Expand Up @@ -338,7 +338,7 @@ const MembersTab: React.FC<MembersTabProps> = ({
choices={ROLE_CHOICES}
showLabel={false}
disabled={changingRole === member.id}
className="!py-1 !pl-2 !pr-8 text-sm"
className="!py-1 !ps-2 !pe-8 text-sm"
/>
</div>
) : (
Expand All @@ -350,32 +350,32 @@ const MembersTab: React.FC<MembersTabProps> = ({
)}

{isTeacher && (
<div className="flex items-center gap-2">
<div className="flex items-center gap-1">
{member.status === "pending" && (
<>
<button
onClick={() => handleApprove(member)}
className="p-1.5 text-green-600 hover:bg-green-50 dark:hover:bg-green-900/20 rounded-lg transition-colors cursor-pointer"
className="p-2.5 text-green-600 hover:bg-green-50 dark:hover:bg-green-900/20 rounded-lg transition-colors cursor-pointer"
aria-label={t("course.detail.members.approve")}
>
<HiCheck className="w-4 h-4" />
<HiCheck className="w-5 h-5" />
</button>
<button
onClick={() => handleDeny(member)}
className="p-1.5 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors cursor-pointer"
className="p-2.5 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors cursor-pointer"
aria-label={t("course.detail.members.deny")}
>
<HiXMark className="w-4 h-4" />
<HiXMark className="w-5 h-5" />
</button>
</>
)}
{member.user !== currentUserId && (
<button
onClick={() => setRemoveMember(member)}
className="p-1.5 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors cursor-pointer"
className="p-2.5 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors cursor-pointer"
aria-label={t("course.detail.members.remove")}
>
<HiTrash className="w-4 h-4" />
<HiTrash className="w-5 h-5" />
</button>
)}
</div>
Expand Down
18 changes: 9 additions & 9 deletions Frontend/EduLiteFrontend/src/components/courses/ModulesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,47 +192,47 @@ const ModulesTab: React.FC<ModulesTabProps> = ({

{/* Teacher actions */}
{isTeacher && (
<div className="flex items-center gap-1 flex-shrink-0">
<div className="flex items-center gap-0.5 sm:gap-1 flex-shrink-0">
{/* Reorder */}
<button
onClick={() => handleReorder(mod, "up")}
disabled={idx === 0 || reordering !== null}
className="p-1.5 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600/30 rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed cursor-pointer"
className="p-2.5 sm:p-1.5 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600/30 rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed cursor-pointer"
aria-label={t("course.detail.modules.moveUp")}
title={t("course.detail.modules.moveUp")}
>
<HiChevronUp className="w-4 h-4" />
<HiChevronUp className="w-5 h-5 sm:w-4 sm:h-4" />
</button>
<button
onClick={() => handleReorder(mod, "down")}
disabled={
idx === moduleList.length - 1 || reordering !== null
}
className="p-1.5 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600/30 rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed cursor-pointer"
className="p-2.5 sm:p-1.5 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600/30 rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed cursor-pointer"
aria-label={t("course.detail.modules.moveDown")}
title={t("course.detail.modules.moveDown")}
>
<HiChevronDown className="w-4 h-4" />
<HiChevronDown className="w-5 h-5 sm:w-4 sm:h-4" />
</button>

{/* Edit */}
<button
onClick={() => setEditModule(mod)}
className="p-1.5 text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors cursor-pointer"
className="p-2.5 sm:p-1.5 text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors cursor-pointer"
aria-label={t("course.detail.modules.edit")}
title={t("course.detail.modules.edit")}
>
<HiPencil className="w-4 h-4" />
<HiPencil className="w-5 h-5 sm:w-4 sm:h-4" />
</button>

{/* Delete */}
<button
onClick={() => setDeleteModule(mod)}
className="p-1.5 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors cursor-pointer"
className="p-2.5 sm:p-1.5 text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors cursor-pointer"
aria-label={t("course.detail.modules.delete")}
title={t("course.detail.modules.delete")}
>
<HiTrash className="w-4 h-4" />
<HiTrash className="w-5 h-5 sm:w-4 sm:h-4" />
</button>
</div>
)}
Expand Down
1 change: 1 addition & 0 deletions Frontend/EduLiteFrontend/src/i18n/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
"filterCountry": "البلد",
"filterVisibility": "الظهور",
"clearFilters": "مسح الفلاتر",
"filtersLabel": "فلاتر",
"visibilityPublic": "عامة",
"visibilityRestricted": "مقيدة",
"visibilityPrivate": "خاصة"
Expand Down
1 change: 1 addition & 0 deletions Frontend/EduLiteFrontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@
"filterCountry": "Country",
"filterVisibility": "Visibility",
"clearFilters": "Clear filters",
"filtersLabel": "Filters",
"visibilityPublic": "Public",
"visibilityRestricted": "Restricted",
"visibilityPrivate": "Private"
Expand Down
24 changes: 14 additions & 10 deletions Frontend/EduLiteFrontend/src/pages/CourseDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -738,24 +738,24 @@ const CourseDetailPage = () => {
{/* ===== SAVE CHANGES BANNER ===== */}
{isEditing && isDirty && (
<div className="p-4 bg-amber-50 dark:bg-amber-900/20 border-b border-amber-200 dark:border-amber-800">
<div className="flex items-center justify-between">
<div className="flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-3">
<div className="flex items-center gap-3">
<div className="w-2 h-2 bg-amber-500 rounded-full animate-pulse"></div>
<div className="w-2 h-2 bg-amber-500 rounded-full animate-pulse flex-shrink-0"></div>
<p className="text-amber-800 dark:text-amber-200 font-medium">
{t("course.detail.unsavedChanges")}
</p>
</div>
<div className="flex items-center gap-3">
<button
onClick={handleCancelEditing}
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors font-medium cursor-pointer"
className="flex-1 sm:flex-none px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors font-medium cursor-pointer"
>
{t("course.detail.cancelButton")}
</button>
<button
onClick={handleSave}
disabled={saving}
className="inline-flex items-center gap-2 px-6 py-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-all shadow-lg hover:shadow-xl disabled:cursor-not-allowed disabled:opacity-50"
className="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-all shadow-lg hover:shadow-xl disabled:cursor-not-allowed disabled:opacity-50"
>
{saving ? (
<>
Expand All @@ -775,21 +775,21 @@ const CourseDetailPage = () => {
)}

{/* ===== ACTION BUTTONS ===== */}
<div className="p-8 border-b border-gray-200/50 dark:border-gray-700/30 bg-gray-50/50 dark:bg-gray-900/20">
<div className="flex flex-wrap gap-4">
<div className="p-4 sm:p-8 border-b border-gray-200/50 dark:border-gray-700/30 bg-gray-50/50 dark:bg-gray-900/20">
<div className="flex flex-col sm:flex-row flex-wrap gap-3 sm:gap-4">
{/* Teacher actions */}
{isTeacher && !isEditing && (
<>
<button
onClick={handleStartEditing}
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 hover:border-blue-500 dark:hover:border-blue-400 text-gray-700 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 rounded-lg font-medium transition-all cursor-pointer"
className="inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 hover:border-blue-500 dark:hover:border-blue-400 text-gray-700 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 rounded-lg font-medium transition-all cursor-pointer w-full sm:w-auto"
>
<HiPencil className="w-5 h-5" />
{t("course.detail.editButton")}
</button>
<button
onClick={() => setShowDeleteModal(true)}
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 hover:border-red-500 dark:hover:border-red-400 text-gray-700 dark:text-gray-200 hover:text-red-600 dark:hover:text-red-400 rounded-lg font-medium transition-all cursor-pointer"
className="inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 hover:border-red-500 dark:hover:border-red-400 text-gray-700 dark:text-gray-200 hover:text-red-600 dark:hover:text-red-400 rounded-lg font-medium transition-all cursor-pointer w-full sm:w-auto"
>
<HiTrash className="w-5 h-5" />
{t("course.detail.deleteButton")}
Expand All @@ -800,15 +800,19 @@ const CourseDetailPage = () => {
{isEditing && (
<button
onClick={handleCancelEditing}
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 rounded-lg font-medium transition-all hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer"
className="inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 rounded-lg font-medium transition-all hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer w-full sm:w-auto"
>
{t("course.detail.cancelButton")}
</button>
)}

{/* Enrollment actions (join/leave/pending/invited) */}
{!isEditing && (
<EnrollmentActions course={course} enrollment={enrollment} />
<EnrollmentActions
course={course}
enrollment={enrollment}
className="w-full sm:w-auto"
/>
)}
</div>
</div>
Expand Down
Loading
Loading