Skip to content

Commit

Permalink
Merge pull request #280 from COS301-SE-2024/update/loading
Browse files Browse the repository at this point in the history
Update/loading
  • Loading branch information
bukhosi-eugene-mpande authored Oct 1, 2024
2 parents 9c8b87c + b2e177d commit 0193ae2
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 149 deletions.
47 changes: 17 additions & 30 deletions src/src/lib/components/workspaces/workspace/Sidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
type NavLink = { name: string; href: string };
interface LecturerLinks {
dashboard: NavLink[];
announcements: NavLink[];
management: NavLink[];
resources: NavLink[];
}
interface StudentLinks {
announcements: NavLink[];
courseWork: NavLink[];
additional: NavLink[];
}
Expand All @@ -36,25 +37,24 @@
const navLinks: NavLinks = {
lecturer: {
dashboard: [{ name: 'Dashboard', href: workspaceURL + '/dashboard' }],
announcements: [{ name: 'Announcements', href: workspaceURL + '/announcements' }],
management: [
{ name: 'Grade Center', href: workspaceURL + '/gradecenter' },
{ name: 'Announcements', href: workspaceURL + '/announcements' },
{ name: 'Materials', href: workspaceURL + '/materials' },
{ name: 'Lessons', href: workspaceURL + '/lessons' },
{ name: 'Live Sessions', href: workspaceURL + '/lessons' },
{ name: 'Quizzes', href: workspaceURL + '/quizzes' },
{ name: 'Interactive Lessons', href: workspaceURL + '/interactive' }
{ name: 'Practices', href: workspaceURL + '/interactive' }
],
resources: [{ name: 'Environments', href: workspaceURL + '/environments' }]
},
student: {
announcements: [{ name: 'Announcements', href: workspaceURL + '/announcements' }],
courseWork: [
{ name: 'Announcements', href: workspaceURL + '/announcements' },
{ name: 'Activities', href: workspaceURL + '/activities' },
{ name: 'Materials', href: workspaceURL + '/materials' },
{ name: 'Lessons', href: workspaceURL + '/lessons' },
{ name: 'Live Sessions', href: workspaceURL + '/lessons' },
{ name: 'Quizzes', href: workspaceURL + '/quizzes' },
{ name: 'Interactive Lessons', href: workspaceURL + '/interactive' }
{ name: 'Practices', href: workspaceURL + '/interactive' }
],
additional: [
{ name: 'Environments', href: workspaceURL + '/environments' },
Expand All @@ -66,7 +66,7 @@
$: currentLinks = navLinks[role];
function isLecturerLinks(links: LecturerLinks | StudentLinks): links is LecturerLinks {
return 'dashboard' in links;
return 'management' in links;
}
function isStudentLinks(links: LecturerLinks | StudentLinks): links is StudentLinks {
Expand Down Expand Up @@ -94,28 +94,15 @@
</NavBrand>
<NavHamburger />
<NavUl>
{#if isLecturerLinks(currentLinks)}
{#if currentLinks.dashboard.length > 1}
<NavLi class="nav-link cursor-pointer">
Dashboard<ChevronDownOutline
class="ms-2 inline h-6 w-6 text-primary-800 dark:text-white"
/>
</NavLi>
<Dropdown class="z-20 w-44">
{#each currentLinks.dashboard as { name, href }}
<DropdownItem {href}>{name}</DropdownItem>
{/each}
</Dropdown>
{:else}
<NavLi
class="nav-link"
href={currentLinks.dashboard[0].href}
active={activeUrl === currentLinks.dashboard[0].href}
>
{currentLinks.dashboard[0].name}
</NavLi>
{/if}
<NavLi
class="nav-link"
href={currentLinks.announcements[0].href}
active={activeUrl === currentLinks.announcements[0].href}
>
{currentLinks.announcements[0].name}
</NavLi>

{#if isLecturerLinks(currentLinks)}
{#if currentLinks.management.length > 1}
<NavLi class="nav-link cursor-pointer">
Management<ChevronDownOutline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@
<div class="sm:flex sm:items-center sm:justify-between">
<div>
<div class="flex items-center gap-x-3">
<h2 class="text-xl font-bold text-gray-800 dark:text-white">Interactive Lessons</h2>
<h2 class="text-xl font-bold text-gray-800 dark:text-white">Practice Material</h2>
<span
class="rounded-full bg-green-100 px-3 py-1 text-xs text-green-600 dark:bg-gray-800 dark:text-green-400"
>
{interactive.length} Interactive lessons
{interactive.length} Practice material
</span>
</div>
</div>
{#if role === 'lecturer'}
<Button size="sm" on:click={() => (isCreateModalOpen = true)}>Create Assesment</Button>
<Button size="sm" on:click={() => (isCreateModalOpen = true)}>Create Practice Material</Button
>
{/if}
</div>
<br />

{#if interactive.length === 0}
<p class="text-l text-gray-800 dark:text-white">
There are no Interactive lessons scheduled at the moment.
There are no practice material available at the moment.
</p>
{:else}
<InteractiveLessons lessons={interactive} {role} />
Expand Down
199 changes: 148 additions & 51 deletions src/src/routes/(auth)/reset-password/[token]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script lang="ts">
import { page } from '$app/stores';
import { enhance } from '$app/forms';
import { Input, Label, Button, Spinner } from 'flowbite-svelte';
import { Button, Spinner } from 'flowbite-svelte';
import { EyeOutline, EyeSlashOutline } from 'flowbite-svelte-icons';
import { onMount } from 'svelte';
export let form;
Expand All @@ -11,6 +12,7 @@
let loading = false;
let successful = false;
let showPassword = false;
let darkMode = false;
function activateLoading() {
loading = true;
Expand All @@ -23,52 +25,112 @@
if (result.type === 'success') successful = true;
};
}
// Function to update theme
function updateTheme(isDark: boolean) {
darkMode = isDark;
if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
// Initialize theme on mount and set up listener for changes
onMount(() => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
updateTheme(mediaQuery.matches);
// Listen for changes in color scheme preference
mediaQuery.addEventListener('change', (e) => updateTheme(e.matches));
// Cleanup listener on component destroy
return () => mediaQuery.removeEventListener('change', updateTheme);
});
// Function to generate random floating elements
const floatingElements = Array(20)
.fill()
.map(() => ({
size: Math.random() * 100 + 50,
left: Math.random() * 100,
top: Math.random() * 100,
duration: Math.random() * 10 + 5,
delay: Math.random() * 5
}));
</script>

<main
class="flex h-screen flex-col items-center justify-center bg-gradient-to-r from-green-300 to-green-600"
class="relative flex min-h-screen items-center justify-center overflow-hidden bg-gradient-to-br from-green-400 via-green-500 to-emerald-600 p-4 transition-colors duration-300 dark:from-green-800 dark:via-green-900 dark:to-emerald-950 sm:p-6 md:p-8"
>
<div class="align-center flex flex-col items-center justify-center rounded-xl bg-white">
<div class="m-4 flex items-center justify-center">
<img class="w-1/6" src="/images/class-connect-logo.png" alt="ClassConnect logo" />
<h1 class="font-roboto m-4 text-4xl font-bold">ClassConnect</h1>
</div>
<!-- Animated background elements -->
<div class="absolute inset-0 overflow-hidden">
{#each floatingElements as element}
<div
class="animate-float absolute rounded-full bg-white bg-opacity-10 dark:bg-gray-300 dark:bg-opacity-10"
style="width: {element.size}px; height: {element.size}px; left: {element.left}%; top: {element.top}%; animation-duration: {element.duration}s; animation-delay: {element.delay}s;"
/>
{/each}
</div>

{#if successful}
<div class="w-1/2 rounded-xl bg-white bg-opacity-80 p-4">
<div class="p-2 text-center">
<h1 class="text-center text-3xl font-bold">Password Reset</h1>
<!-- Main content -->
<div
class="w-full max-w-md rounded-xl border border-white border-opacity-20 bg-white bg-opacity-10 p-6 shadow-2xl backdrop-blur-lg transition-colors duration-300 dark:border-gray-700 dark:border-opacity-50 dark:bg-gray-800 dark:bg-opacity-30 sm:max-w-lg sm:p-8 md:max-w-xl md:p-10 lg:max-w-2xl lg:p-12"
>
<div class="mb-6 flex justify-center sm:mb-8">
<img
src="/images/class-connect-logo.png"
alt="ClassConnect Logo"
class="h-24 w-24 sm:h-32 sm:w-32 md:h-36 md:w-36 lg:h-40 lg:w-40"
/>
</div>

<p>Your password has been reset successfully.</p>
<h1
class="mb-4 text-center text-3xl font-bold text-white dark:text-gray-100 sm:mb-6 sm:text-4xl"
>
Reset Password
</h1>

<Button href="/signin" class="mt-4">Go back to Sign In</Button>
</div>
{#if successful}
<div class="text-center">
<p class="mb-8 text-lg text-gray-100 dark:text-gray-300 sm:mb-10 sm:text-xl">
Your password has been reset successfully.
</p>
<Button
href="/signin"
class="w-full transform rounded-lg bg-green-600 px-6 py-3 font-semibold text-white transition duration-300 ease-in-out hover:-translate-y-1 hover:bg-green-700 hover:shadow-xl dark:bg-green-700 dark:hover:bg-green-800 sm:w-2/3 md:w-1/2"
>
Go back to Sign In
</Button>
</div>
{:else}
<div class="w-1/2 rounded-xl bg-white bg-opacity-80 p-4">
<div class="p-2 text-center">
<h1 class="text-center text-3xl font-bold">Reset Password</h1>
<p>Enter your new password below.</p>
</div>

{#if form?.error}
<p class="mt-2 text-center text-red-500">{form.error}</p>
{/if}

<form method="POST" use:enhance={activateLoading}>
<input type="hidden" name="token" value={token} />

<Label for="password" class="mb-2 mt-2">New Password</Label>
<p class="mb-8 text-center text-lg text-gray-100 dark:text-gray-300 sm:mb-10 sm:text-xl">
Enter your new password below.
</p>

{#if form?.error}
<p class="mb-4 text-center text-red-500">{form.error}</p>
{/if}

<form method="POST" use:enhance={activateLoading} class="space-y-4">
<input type="hidden" name="token" value={token} />

<div>
<label
for="password"
class="mb-2 block text-sm font-medium text-gray-100 dark:text-gray-300"
>New Password</label
>
<div class="relative">
<Input
<input
type={showPassword ? 'text' : 'password'}
id="password"
name="password"
class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-green-500 focus:ring-green-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-green-500 dark:focus:ring-green-500"
placeholder="•••••••••"
disabled={loading}
required
/>

<button
type="button"
aria-label="Toggle password visibility"
Expand All @@ -82,29 +144,64 @@
{/if}
</button>
</div>
</div>

<Label for="confirmPassword" class="mb-2 mt-2">Confirm New Password</Label>
<div class="relative">
<Input
type="password"
id="confirmPassword"
name="confirmPassword"
placeholder="•••••••••"
disabled={loading}
required
/>
</div>
<div>
<label
for="confirmPassword"
class="mb-2 block text-sm font-medium text-gray-100 dark:text-gray-300"
>Confirm New Password</label
>
<input
type="password"
id="confirmPassword"
name="confirmPassword"
class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-green-500 focus:ring-green-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-green-500 dark:focus:ring-green-500"
placeholder="•••••••••"
disabled={loading}
required
/>
</div>

{#if loading}
<Button disabled class="my-4 w-full">
<Spinner class="me-3" size="4" color="white" data-testid="spinner" />
Resetting Password
</Button>
{:else}
<Button type="submit" class="my-4 w-full">Reset Password</Button>
{/if}
</form>
</div>
{#if loading}
<Button disabled class="w-full">
<Spinner class="me-3" size="4" color="white" data-testid="spinner" />
Resetting Password
</Button>
{:else}
<Button
type="submit"
class="w-full transform rounded-lg bg-green-600 px-6 py-3 font-semibold text-white transition duration-300 ease-in-out hover:-translate-y-1 hover:bg-green-700 hover:shadow-xl dark:bg-green-700 dark:hover:bg-green-800"
>Reset Password</Button
>
{/if}
</form>
{/if}
</div>
</main>

<style>
@keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0px);
}
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
:global(body) {
overflow: auto;
}
:global(.dark) {
color-scheme: dark;
}
</style>
Loading

0 comments on commit 0193ae2

Please sign in to comment.