mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: activity page changes
This commit is contained in:
parent
47b354db12
commit
0b2c4d3ad1
3 changed files with 144 additions and 43 deletions
|
|
@ -3,7 +3,7 @@ import Link from 'next/link'
|
||||||
import { getAPIUrl, getUriWithOrg } from '@services/config/config'
|
import { getAPIUrl, getUriWithOrg } from '@services/config/config'
|
||||||
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
|
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
|
||||||
import VideoActivity from '@components/Objects/Activities/Video/Video'
|
import VideoActivity from '@components/Objects/Activities/Video/Video'
|
||||||
import { BookOpenCheck, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, FileText, Folder, List, Menu, MoreVertical, UserRoundPen, Video, Layers, ListFilter, ListTree, X, Edit2 } from 'lucide-react'
|
import { BookOpenCheck, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, FileText, Folder, List, Menu, MoreVertical, UserRoundPen, Video, Layers, ListFilter, ListTree, X, Edit2, EllipsisVertical } from 'lucide-react'
|
||||||
import { markActivityAsComplete, unmarkActivityAsComplete } from '@services/courses/activity'
|
import { markActivityAsComplete, unmarkActivityAsComplete } from '@services/courses/activity'
|
||||||
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
|
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
|
||||||
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
|
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
|
||||||
|
|
@ -42,6 +42,43 @@ interface ActivityClientProps {
|
||||||
course: any
|
course: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ActivityActions({ activity, activityid, course, orgslug, assignment }: { activity: any, activityid: string, course: any, orgslug: string, assignment: any }) {
|
||||||
|
const session = useLHSession() as any;
|
||||||
|
const { contributorStatus } = useContributorStatus(course.course_uuid);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex space-x-2 items-center">
|
||||||
|
{activity && activity.published == true && activity.content.paid_access != false && (
|
||||||
|
<AuthenticatedClientElement checkMethod="authentication">
|
||||||
|
{activity.activity_type != 'TYPE_ASSIGNMENT' && (
|
||||||
|
<>
|
||||||
|
<MarkStatus
|
||||||
|
activity={activity}
|
||||||
|
activityid={activityid}
|
||||||
|
course={course}
|
||||||
|
orgslug={orgslug}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activity.activity_type == 'TYPE_ASSIGNMENT' && (
|
||||||
|
<>
|
||||||
|
<AssignmentSubmissionProvider assignment_uuid={assignment?.assignment_uuid}>
|
||||||
|
<AssignmentTools
|
||||||
|
assignment={assignment}
|
||||||
|
activity={activity}
|
||||||
|
activityid={activityid}
|
||||||
|
course={course}
|
||||||
|
orgslug={orgslug}
|
||||||
|
/>
|
||||||
|
</AssignmentSubmissionProvider>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</AuthenticatedClientElement>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ActivityClient(props: ActivityClientProps) {
|
function ActivityClient(props: ActivityClientProps) {
|
||||||
const activityid = props.activityid
|
const activityid = props.activityid
|
||||||
const courseuuid = props.courseuuid
|
const courseuuid = props.courseuuid
|
||||||
|
|
@ -131,6 +168,24 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{activity && activity.published == true && activity.content.paid_access != false && (
|
||||||
|
<AuthenticatedClientElement checkMethod="authentication">
|
||||||
|
{ (
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<PreviousActivityButton
|
||||||
|
course={course}
|
||||||
|
currentActivityId={activity.id}
|
||||||
|
orgslug={orgslug}
|
||||||
|
/>
|
||||||
|
<NextActivityButton
|
||||||
|
course={course}
|
||||||
|
currentActivityId={activity.id}
|
||||||
|
orgslug={orgslug}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</AuthenticatedClientElement>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ActivityIndicators
|
<ActivityIndicators
|
||||||
|
|
@ -140,8 +195,8 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
course={course}
|
course={course}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center w-full">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex flex-1/3 items-center space-x-3">
|
||||||
<ActivityChapterDropdown
|
<ActivityChapterDropdown
|
||||||
course={course}
|
course={course}
|
||||||
currentActivityId={activity.activity_uuid ? activity.activity_uuid.replace('activity_', '') : activityid.replace('activity_', '')}
|
currentActivityId={activity.activity_uuid ? activity.activity_uuid.replace('activity_', '') : activityid.replace('activity_', '')}
|
||||||
|
|
@ -156,7 +211,7 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-2 items-center">
|
<div className="flex space-x-2 items-center">
|
||||||
{activity && activity.published == true && activity.content.paid_access != false && (
|
{activity && activity.published == true && activity.content.paid_access != false && (
|
||||||
<AuthenticatedClientElement checkMethod="authentication">
|
<AuthenticatedClientElement checkMethod="authentication">
|
||||||
{activity.activity_type != 'TYPE_ASSIGNMENT' && (
|
{activity.activity_type != 'TYPE_ASSIGNMENT' && (
|
||||||
|
|
@ -168,30 +223,9 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
className="bg-emerald-600 rounded-full px-5 drop-shadow-md flex items-center space-x-2 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
className="bg-emerald-600 rounded-full px-5 drop-shadow-md flex items-center space-x-2 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
||||||
>
|
>
|
||||||
<Edit2 size={17} />
|
<Edit2 size={17} />
|
||||||
<span className="text-xs font-bold">Contribute to Activity</span>
|
<span className="text-xs font-bold">Contribute</span>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<MoreVertical size={17} className="text-gray-300" />
|
|
||||||
<MarkStatus
|
|
||||||
activity={activity}
|
|
||||||
activityid={activityid}
|
|
||||||
course={course}
|
|
||||||
orgslug={orgslug}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{activity.activity_type == 'TYPE_ASSIGNMENT' && (
|
|
||||||
<>
|
|
||||||
<MoreVertical size={17} className="text-gray-300 " />
|
|
||||||
<AssignmentSubmissionProvider assignment_uuid={assignment?.assignment_uuid}>
|
|
||||||
<AssignmentTools
|
|
||||||
assignment={assignment}
|
|
||||||
activity={activity}
|
|
||||||
activityid={activityid}
|
|
||||||
course={course}
|
|
||||||
orgslug={orgslug}
|
|
||||||
/>
|
|
||||||
</AssignmentSubmissionProvider>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</AuthenticatedClientElement>
|
</AuthenticatedClientElement>
|
||||||
|
|
@ -250,6 +284,18 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Activity Actions below the content box */}
|
||||||
|
{activity && activity.published == true && activity.content.paid_access != false && (
|
||||||
|
<div className="flex justify-end mt-4">
|
||||||
|
<ActivityActions
|
||||||
|
activity={activity}
|
||||||
|
activityid={activityid}
|
||||||
|
course={course}
|
||||||
|
orgslug={orgslug}
|
||||||
|
assignment={assignment}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Fixed Activity Secondary Bar */}
|
{/* Fixed Activity Secondary Bar */}
|
||||||
{activity && activity.published == true && activity.content.paid_access != false && (
|
{activity && activity.published == true && activity.content.paid_access != false && (
|
||||||
|
|
@ -483,15 +529,66 @@ function NextActivityButton({ course, currentActivityId, orgslug }: { course: an
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolTip content={`Next: ${nextActivity.name}`} side="top">
|
<div
|
||||||
<div
|
onClick={navigateToActivity}
|
||||||
onClick={navigateToActivity}
|
className="bg-white rounded-full px-5 nice-shadow flex items-center space-x-1 p-2.5 text-gray-600 hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
||||||
className="bg-gray-300 rounded-full px-5 nice-shadow flex items-center space-x-2 p-2.5 text-gray-600 hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
>
|
||||||
>
|
<span className="text-xs font-bold text-gray-500">Next</span>
|
||||||
{!isMobile && <span className="text-xs font-bold">Next</span>}
|
<EllipsisVertical className='text-gray-400' size={13} />
|
||||||
<ChevronRight size={17} />
|
<span className="text-sm font-semibold truncate max-w-[200px]">{nextActivity.name}</span>
|
||||||
</div>
|
<ChevronRight size={17} />
|
||||||
</ToolTip>
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PreviousActivityButton({ course, currentActivityId, orgslug }: { course: any, currentActivityId: string, orgslug: string }) {
|
||||||
|
const router = useRouter();
|
||||||
|
const isMobile = useMediaQuery('(max-width: 768px)');
|
||||||
|
|
||||||
|
const findPreviousActivity = () => {
|
||||||
|
let allActivities: any[] = [];
|
||||||
|
let currentIndex = -1;
|
||||||
|
|
||||||
|
// Flatten all activities from all chapters
|
||||||
|
course.chapters.forEach((chapter: any) => {
|
||||||
|
chapter.activities.forEach((activity: any) => {
|
||||||
|
const cleanActivityUuid = activity.activity_uuid?.replace('activity_', '');
|
||||||
|
allActivities.push({
|
||||||
|
...activity,
|
||||||
|
cleanUuid: cleanActivityUuid,
|
||||||
|
chapterName: chapter.name
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if this is the current activity
|
||||||
|
if (activity.id === currentActivityId) {
|
||||||
|
currentIndex = allActivities.length - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get previous activity
|
||||||
|
return currentIndex > 0 ? allActivities[currentIndex - 1] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const previousActivity = findPreviousActivity();
|
||||||
|
|
||||||
|
if (!previousActivity) return null;
|
||||||
|
|
||||||
|
const navigateToActivity = () => {
|
||||||
|
const cleanCourseUuid = course.course_uuid?.replace('course_', '');
|
||||||
|
router.push(getUriWithOrg(orgslug, '') + `/course/${cleanCourseUuid}/activity/${previousActivity.cleanUuid}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={navigateToActivity}
|
||||||
|
className="bg-white rounded-full px-5 nice-shadow flex items-center space-x-1 p-2.5 text-gray-600 hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
||||||
|
>
|
||||||
|
<ChevronLeft size={17} />
|
||||||
|
<span className="text-xs font-bold text-gray-500">Previous</span>
|
||||||
|
<EllipsisVertical className='text-gray-400' size={13} />
|
||||||
|
<span className="text-sm font-semibold truncate max-w-[200px]">{previousActivity.name}</span>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -160,11 +160,7 @@ export default function FixedActivitySecondaryBar(props: FixedActivitySecondaryB
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => navigateToActivity(nextActivity)}
|
onClick={() => navigateToActivity(nextActivity)}
|
||||||
className={`flex items-center space-x-1 sm:space-x-2 py-1.5 px-1.5 sm:px-2 rounded-md transition-all duration-200 ${
|
className={`flex items-center space-x-1 sm:space-x-2 py-1.5 px-1.5 sm:px-2 rounded-md transition-all duration-200`}
|
||||||
nextActivity
|
|
||||||
? 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
|
||||||
: 'text-gray-300 cursor-not-allowed'
|
|
||||||
}`}
|
|
||||||
disabled={!nextActivity}
|
disabled={!nextActivity}
|
||||||
title={nextActivity ? `Next: ${nextActivity.name}` : 'No next activity'}
|
title={nextActivity ? `Next: ${nextActivity.name}` : 'No next activity'}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@ import toast from 'react-hot-toast';
|
||||||
|
|
||||||
export type ContributorStatus = 'NONE' | 'PENDING' | 'ACTIVE' | 'INACTIVE';
|
export type ContributorStatus = 'NONE' | 'PENDING' | 'ACTIVE' | 'INACTIVE';
|
||||||
|
|
||||||
|
interface Contributor {
|
||||||
|
user_id: string;
|
||||||
|
authorship_status: ContributorStatus;
|
||||||
|
}
|
||||||
|
|
||||||
export function useContributorStatus(courseUuid: string) {
|
export function useContributorStatus(courseUuid: string) {
|
||||||
const session = useLHSession() as any;
|
const session = useLHSession() as any;
|
||||||
const [contributorStatus, setContributorStatus] = useState<ContributorStatus>('NONE');
|
const [contributorStatus, setContributorStatus] = useState<ContributorStatus>('NONE');
|
||||||
|
|
@ -22,9 +27,9 @@ export function useContributorStatus(courseUuid: string) {
|
||||||
session.data?.tokens?.access_token
|
session.data?.tokens?.access_token
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response && response.data) {
|
if (response && response.data && Array.isArray(response.data)) {
|
||||||
const currentUser = response.data.find(
|
const currentUser = response.data.find(
|
||||||
(contributor: any) => contributor.user_id === session.data.user.id
|
(contributor: Contributor) => contributor.user_id === session.data.user.id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (currentUser) {
|
if (currentUser) {
|
||||||
|
|
@ -32,10 +37,13 @@ export function useContributorStatus(courseUuid: string) {
|
||||||
} else {
|
} else {
|
||||||
setContributorStatus('NONE');
|
setContributorStatus('NONE');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setContributorStatus('NONE');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to check contributor status:', error);
|
console.error('Failed to check contributor status:', error);
|
||||||
toast.error('Failed to check contributor status');
|
toast.error('Failed to check contributor status');
|
||||||
|
setContributorStatus('NONE');
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue