CLASSROOMIO-T-45: Basic Landing Page for subdomains
Co-authored-by: Rotimi Best <[email protected]> Merge-request: CLASSROOMIO-MR-10 Merged-by: Digdippa Team <[email protected]>
This commit is contained in:
committed by
Space Cloud
co-authored by
Rotimi Best
parent
30d019ac51
commit
4f213181ce
@@ -4,9 +4,11 @@
|
||||
import { ROLE } from '../../../../utils/constants/roles';
|
||||
import getCurrencyFormatter from '../../../../utils/functions/getCurrencyFormatter';
|
||||
import OverflowMenuHorizontal24 from 'carbon-icons-svelte/lib/OverflowMenuHorizontal24';
|
||||
import ArrowRight from 'carbon-icons-svelte/lib/ArrowRight24';
|
||||
|
||||
export let bannerImage: string | undefined;
|
||||
export let id = '';
|
||||
export let slug = '';
|
||||
export let title = '';
|
||||
export let description = '';
|
||||
export let role_id = ROLE.STUDENT;
|
||||
@@ -14,6 +16,7 @@
|
||||
export let cost = 0;
|
||||
export let totalLessons = 0;
|
||||
export let currency = 'NGN';
|
||||
export let isOnLandingPage = false;
|
||||
|
||||
let formatter = getCurrencyFormatter(currency);
|
||||
|
||||
@@ -42,25 +45,31 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<a rel="prefetch" href="/courses/{id}" class=" text-black">
|
||||
<a
|
||||
rel="prefetch"
|
||||
href={isOnLandingPage ? `/course/${slug}` : `/courses/${id}`}
|
||||
class=" text-black"
|
||||
>
|
||||
<div
|
||||
class="root w-72 border bg-gray-100 dark:bg-gray-700 mr-4 mb-4 rounded-md transition ease-in-out relative"
|
||||
class="root w-80 border bg-gray-100 dark:bg-gray-700 sm:mr-4 mb-4 rounded-md hover:shadow-2xl transition ease-in-out relative"
|
||||
>
|
||||
<Dropdown
|
||||
options={getOptions()}
|
||||
classNames="absolute top-4 right-4"
|
||||
isIcon={true}
|
||||
>
|
||||
<div class="p-1 rounded-full bg-white dark:bg-gray-600">
|
||||
<OverflowMenuHorizontal24 class="carbon-icon" />
|
||||
</div>
|
||||
</Dropdown>
|
||||
{#if !isOnLandingPage}
|
||||
<Dropdown
|
||||
options={getOptions()}
|
||||
classNames="absolute top-4 right-4"
|
||||
isIcon={true}
|
||||
>
|
||||
<div class="p-1 rounded-full bg-white dark:bg-gray-600">
|
||||
<OverflowMenuHorizontal24 class="carbon-icon" />
|
||||
</div>
|
||||
</Dropdown>
|
||||
{/if}
|
||||
<img
|
||||
class="h-2/5 w-full rounded-tl rounded-tr"
|
||||
src={bannerImage ?? '/images/classroomio-course-img-template.jpg'}
|
||||
alt="Course Logo"
|
||||
/>
|
||||
<div class="p-3 pb-0">
|
||||
<div class="px-3 py-5">
|
||||
<h4 class="dark:text-white title text-md font-bold">
|
||||
{title}
|
||||
</h4>
|
||||
@@ -72,13 +81,18 @@
|
||||
</p>
|
||||
<div class="flex justify-between">
|
||||
<p class="dark:text-white">{totalLessons} lessons</p>
|
||||
<div class="rounded bg-{isPublished ? 'green' : 'red'}-200 py-1 px-2">
|
||||
{#if isPublished}
|
||||
Published
|
||||
{:else}
|
||||
Unpublished
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if isOnLandingPage}
|
||||
<ArrowRight class="carbon-class" />
|
||||
{:else}
|
||||
<div class="rounded bg-{isPublished ? 'green' : 'red'}-200 py-1 px-2">
|
||||
{#if isPublished}
|
||||
Published
|
||||
{:else}
|
||||
Unpublished
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="dark:text-white text-gray-500 text-xs mt-1">
|
||||
{!cost ? 'free' : formatter.format(cost)}
|
||||
@@ -92,7 +106,8 @@
|
||||
min-height: 370px;
|
||||
}
|
||||
|
||||
a {
|
||||
a,
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.title,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
|
||||
{#if $user.isLoggedIn}
|
||||
<li class="">
|
||||
<li class="hidden">
|
||||
<a
|
||||
class="block"
|
||||
aria-current={segment === undefined || segment === 'dashboard'
|
||||
@@ -40,7 +40,7 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<li class="hidden">
|
||||
<a
|
||||
class="block"
|
||||
aria-current={segment === 'courses' ? 'page' : undefined}
|
||||
|
||||
@@ -1,4 +1,163 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { Search } from 'carbon-components-svelte';
|
||||
import LogoFacebook from 'carbon-icons-svelte/lib/LogoFacebook24';
|
||||
import LogoTwitter from 'carbon-icons-svelte/lib/LogoTwitter24';
|
||||
import LogoLinkedin from 'carbon-icons-svelte/lib/LogoLinkedin24';
|
||||
|
||||
import Navigation from '../../Navigation/index.svelte';
|
||||
import Box from '../../Box/index.svelte';
|
||||
import Card from '../../Courses/components/Card/index.svelte';
|
||||
import CardLoader from '../../Courses/components/Card/Loader.svelte';
|
||||
import CoursesEmptyIcon from '../../Icons/CoursesEmptyIcon.svelte';
|
||||
import { courses, courseMetaDeta } from '../../Courses/store';
|
||||
import { getCourseBySiteName } from '../../../utils/services/org';
|
||||
import { appStore } from '../../../utils/store/app';
|
||||
|
||||
export let segment;
|
||||
|
||||
let searchValue = '';
|
||||
|
||||
onMount(async () => {
|
||||
console.log('sitename', $appStore.siteNameFromDomain);
|
||||
$courseMetaDeta.isLoading = true;
|
||||
const coursesResult = await getCourseBySiteName(
|
||||
$appStore.siteNameFromDomain
|
||||
);
|
||||
courses.set(coursesResult);
|
||||
$courseMetaDeta.isLoading = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<Navigation {segment} />
|
||||
|
||||
<!-- Header Section -->
|
||||
<header class="banner w-full flex items-center justify-center p-">
|
||||
<div
|
||||
class="w-full flex items-center justify-center flex-col-reverse md:flex-row"
|
||||
>
|
||||
<!-- Course Description -->
|
||||
<div class="course-descr w-11/12 py-10">
|
||||
<h1
|
||||
class="dark:text-white text-5xl text-white text-center my-4 font-bold"
|
||||
>
|
||||
Explore courses
|
||||
</h1>
|
||||
<p class="dark:text-white text-md text-white mb-6 text-center">
|
||||
Find courses you will love from best teachers all over the world🌎.
|
||||
</p>
|
||||
|
||||
<Search placeholder="Find a course..." bind:value={searchValue} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="my-10 mx-auto max-w-6xl w-full">
|
||||
<div class="flex items-center justify-evenly flex-wrap my-4 m-auto">
|
||||
{#if $courseMetaDeta.isLoading}
|
||||
<CardLoader />
|
||||
<CardLoader />
|
||||
<CardLoader />
|
||||
{:else}
|
||||
{#each $courses as courseData}
|
||||
<Card
|
||||
id={courseData.id}
|
||||
slug={courseData.slug}
|
||||
logo={courseData.logo}
|
||||
bannerImage={courseData.banner_image}
|
||||
title={courseData.title}
|
||||
description={courseData.description}
|
||||
role_id={courseData.role_id}
|
||||
isPublished={courseData.is_published}
|
||||
cost={courseData.cost}
|
||||
currency={courseData.currency}
|
||||
totalLessons={courseData.total_lessons}
|
||||
isOnLandingPage={true}
|
||||
/>
|
||||
{:else}
|
||||
<Box>
|
||||
<CoursesEmptyIcon />
|
||||
<h3 class="dark:text-white text-2xl my-5">No Courses Created</h3>
|
||||
<p class="dark:text-white w-1/3 text-center">
|
||||
We've got great courses coming your way, stay tuned!!!
|
||||
</p>
|
||||
</Box>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer
|
||||
class="flex justify-center mt-10 w-full px-5 py-5 sm:py-10 border-b-0 border-r-0 border-t border-l-0 border-gray-300"
|
||||
>
|
||||
<ul class="flex w-11/12 items-center flex-col sm:flex-row">
|
||||
<div class="logo">
|
||||
<a
|
||||
href="/"
|
||||
title="Go to ClassroomIO Home"
|
||||
id="logo"
|
||||
data-hveid="8"
|
||||
class="flex items-center"
|
||||
>
|
||||
<img
|
||||
src="/logo-192.png"
|
||||
alt="ClassroomIO logo"
|
||||
class="rounded h-10 w-10 inline-block mx-auto"
|
||||
data-atf="1"
|
||||
/>
|
||||
<h3 class="text-black ml-3">Classroomio</h3>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span class="flex-grow" />
|
||||
|
||||
<div class="flex mt-5 sm:mt-0">
|
||||
<li class="mx-2">
|
||||
<a
|
||||
href="facebook.com"
|
||||
target="_blank"
|
||||
title="Facebook"
|
||||
id="logo-fb"
|
||||
data-hveid="8"
|
||||
>
|
||||
<LogoFacebook />
|
||||
</a>
|
||||
</li>
|
||||
<li class="mx-2">
|
||||
<a
|
||||
href="twitter.com"
|
||||
target="_blank"
|
||||
title="Twitter"
|
||||
id="logo-tw"
|
||||
data-hveid="8"
|
||||
>
|
||||
<LogoTwitter />
|
||||
</a>
|
||||
</li>
|
||||
<li class="mx-2">
|
||||
<a
|
||||
href="linkedin.com"
|
||||
target="_blank"
|
||||
title="Linkedin"
|
||||
id="logo-ln"
|
||||
data-hveid="8"
|
||||
>
|
||||
<LogoLinkedin />
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<style lang="scss">
|
||||
.banner {
|
||||
background-color: #040f2d;
|
||||
min-height: 337px;
|
||||
}
|
||||
|
||||
.course-descr {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
+52
-56
@@ -15,6 +15,7 @@
|
||||
import Tailwindcss from '../components/Tailwindcss.svelte';
|
||||
import LandingNavigation from '../components/Navigation/index.svelte';
|
||||
import OrgNavigation from '../components/Navigation/app.svelte';
|
||||
import OrgLandingPage from '../components/Org/LandingPage/index.svelte';
|
||||
import Snackbar from '../components/Snackbar/index.svelte';
|
||||
import Backdrop from '../components/Backdrop/index.svelte';
|
||||
import OrgSideBar from '../components/Org/SideBar.svelte';
|
||||
@@ -39,7 +40,6 @@
|
||||
let supabase = getSupabase(config);
|
||||
let path = $page.path.replace('/', '');
|
||||
let theme = 'white';
|
||||
let isStudentDomain = false;
|
||||
|
||||
const delayedPreloading = derived(preloading, (currentPreloading, set) => {
|
||||
setTimeout(() => set(currentPreloading), 250);
|
||||
@@ -100,26 +100,31 @@
|
||||
|
||||
const orgRes = await getOrganizations($profile.id);
|
||||
|
||||
// If user coming to login page, then
|
||||
if (isEmpty(orgRes.orgs)) {
|
||||
goto(ROUTE.ONBOARDING);
|
||||
} else if (
|
||||
['login', 'signup', 'onboarding'].includes(path) ||
|
||||
path === '' // for home page
|
||||
) {
|
||||
// By default redirect to first organization
|
||||
goto(`/org/${orgRes.currentOrg.siteName}`);
|
||||
if ($appStore.isStudentDomain) {
|
||||
// student redirect
|
||||
} else {
|
||||
// If user coming to login page, then
|
||||
if (isEmpty(orgRes.orgs)) {
|
||||
goto(ROUTE.ONBOARDING);
|
||||
} else if (
|
||||
['login', 'signup', 'onboarding'].includes(path) ||
|
||||
path === '' // for home page
|
||||
) {
|
||||
// By default redirect to first organization
|
||||
goto(`/org/${orgRes.currentOrg.siteName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getIsStudentDomain(host) {
|
||||
function setOrgBasedOnUrl(host) {
|
||||
if (typeof window !== 'undefined') {
|
||||
const debug = localStorage.getItem('role') === 'student';
|
||||
const matches = host.match(/([a-z0-9]+).*classroomio[.]com/);
|
||||
const answer = Array.isArray(matches) ? !!matches[1] : false;
|
||||
|
||||
return debug || answer;
|
||||
$appStore.isStudentDomain = debug || answer;
|
||||
$appStore.siteNameFromDomain = debug ? 'startupscoo' : matches?.[1] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +144,7 @@
|
||||
console.log(
|
||||
'Welcome to ClassroomIO, we are grateful you chose us.',
|
||||
$page.host,
|
||||
`\nIs student domain: ${isStudentDomain}`
|
||||
`\nIs student domain: ${$appStore.isStudentDomain}`
|
||||
);
|
||||
// Disable GA on localhost
|
||||
if (config && !config.isProd) {
|
||||
@@ -183,21 +188,9 @@
|
||||
};
|
||||
});
|
||||
|
||||
// if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
||||
// page.subscribe(() => {
|
||||
// const from = window.location.pathname;
|
||||
// const redirect = (href) => {
|
||||
// goto(href);
|
||||
// };
|
||||
// if (!$user.isLoggedIn && !PUBLIC_ROUTES.includes(from)) {
|
||||
// redirect('/login');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
$: path = $page.path.replace('/', '');
|
||||
$: theme = $appStore.isDark ? 'g100' : 'white';
|
||||
$: isStudentDomain = getIsStudentDomain($page.host);
|
||||
$: setOrgBasedOnUrl($page.host);
|
||||
</script>
|
||||
|
||||
<svelte:window on:resize={handleResize} />
|
||||
@@ -209,43 +202,46 @@
|
||||
<Theme bind:theme />
|
||||
<Tailwindcss />
|
||||
|
||||
<!-- <Nav {segment} /> -->
|
||||
<Snackbar />
|
||||
|
||||
<main class="dark:bg-gray-800">
|
||||
{#if $preloading && $delayedPreloading}
|
||||
<Backdrop>
|
||||
<Moon size="60" color="#1d4ed8" unit="px" duration="1s" />
|
||||
</Backdrop>
|
||||
{/if}
|
||||
{#if !ROUTES_TO_HIDE_NAV.includes($page.path) && !isCoursePage(path)}
|
||||
{#if $page.path.includes('org') || $page.path.includes('profile')}
|
||||
<OrgNavigation />
|
||||
{:else}
|
||||
<LandingNavigation {segment} />
|
||||
{#if $appStore.isStudentDomain && !path}
|
||||
<OrgLandingPage {segment} />
|
||||
{:else}
|
||||
<main class="dark:bg-gray-800">
|
||||
{#if $preloading && $delayedPreloading}
|
||||
<Backdrop>
|
||||
<Moon size="60" color="#1d4ed8" unit="px" duration="1s" />
|
||||
</Backdrop>
|
||||
{/if}
|
||||
{#if !ROUTES_TO_HIDE_NAV.includes($page.path) && !isCoursePage(path)}
|
||||
{#if $page.path.includes('org') || $page.path.includes('profile')}
|
||||
<OrgNavigation />
|
||||
{:else}
|
||||
<LandingNavigation {segment} />
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<div class="flex justify-between">
|
||||
{#if isOrgPage($page.path)}
|
||||
<div class="org-root w-full flex items-center justify-between">
|
||||
<OrgSideBar />
|
||||
<div class="org-slot bg-white dark:bg-gray-800">
|
||||
<slot />
|
||||
<div class="flex justify-between">
|
||||
{#if isOrgPage($page.path)}
|
||||
<div class="org-root w-full flex items-center justify-between">
|
||||
<OrgSideBar />
|
||||
<div class="org-slot bg-white dark:bg-gray-800">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
|
||||
{#if showAppsSideBar(path)}
|
||||
<Apps />
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
{#if showAppsSideBar(path)}
|
||||
<Apps />
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{#if !['about', ''].includes(path)}
|
||||
<!-- <Footer {segment} /> -->
|
||||
{#if !['about', ''].includes(path)}
|
||||
<!-- <Footer {segment} /> -->
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
@@ -54,7 +54,7 @@ export async function fetchCourse(
|
||||
console.log(`data`, data);
|
||||
console.log(`fetchCourse => error`, error);
|
||||
// return this.redirect(301, '/courses');
|
||||
return;
|
||||
return { data, error };
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -122,3 +122,24 @@ export async function getOrgAudience(orgId) {
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getCourseBySiteName(siteName) {
|
||||
const { data, error } = await supabase
|
||||
.from('course')
|
||||
.select(
|
||||
`
|
||||
*,
|
||||
group!inner(
|
||||
organization!inner(id, name, siteName, avatar_url)
|
||||
)
|
||||
`
|
||||
)
|
||||
.eq('group.organization.siteName', siteName)
|
||||
.eq('is_published', true);
|
||||
|
||||
if (error) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@ import { writable } from 'svelte/store';
|
||||
|
||||
export const appStore = writable({
|
||||
isDark: false,
|
||||
isStudentDomain: false,
|
||||
siteNameFromDomain: '',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user