CLASSROOMIO-T-46: Forum CRUD MVP

Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com>

Merge-request: CLASSROOMIO-MR-13
Merged-by: Digdippa Team <digdippa@gmail.com>
This commit is contained in:
Rotimi Best
2023-05-20 23:53:28 +00:00
committed by Space Cloud
co-authored by Rotimi Best
parent 779827ba46
commit c36a49a1ee
42 changed files with 871 additions and 1573 deletions
+8 -4
View File
@@ -1,5 +1,4 @@
<script>
import { onMount } from 'svelte';
import Box from '../../Box/index.svelte';
import AudienceList from './AudienceList.svelte';
import AudienceEmptyIcon from '../../Icons/AudienceEmptyIcon.svelte';
@@ -7,11 +6,16 @@
import { orgAudience, currentOrg } from '../../../utils/store/org';
let isLoading = false;
onMount(async () => {
async function fetchInitData(orgId) {
if (!orgId) return;
isLoading = true;
await getOrgAudience($currentOrg.id);
await getOrgAudience(orgId);
isLoading = false;
});
}
$: fetchInitData($currentOrg.id);
</script>
<div
@@ -0,0 +1,37 @@
<script>
import Modal from '../../Modal/index.svelte';
import PrimaryButton from '../../PrimaryButton/index.svelte';
import { VARIANTS } from '../../PrimaryButton/constants';
export let onDelete = () => {};
export let onCancel = () => {};
export let open = false;
</script>
<Modal
onClose={() => (open = false)}
bind:open
width="w-96"
modalHeading="Delete comment"
>
<div>
<h1 class="dark:text-white text-lg">
Are you sure you want to delete this comment?
</h1>
<div class="mt-5 flex items-center justify-between">
<PrimaryButton
className="px-6 py-3"
variant={VARIANTS.OUTLINED}
label="No, keep it"
onClick={onCancel}
/>
<PrimaryButton
className="px-6 py-3"
variant={VARIANTS.CONTAINED_DANGER}
label="Yes, delete"
onClick={onDelete}
/>
</div>
</div>
</Modal>
+110
View File
@@ -0,0 +1,110 @@
<script>
import { goto } from '@sapper/app';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import AddComment20 from 'carbon-icons-svelte/lib/AddComment20';
import Vote from '../../Vote/index.svelte';
import Box from '../../Box/index.svelte';
import CoursesEmptyIcon from '../../Icons/CoursesEmptyIcon.svelte';
import Space from '../../Space/index.svelte';
import { currentOrgPath, currentOrg } from '../../../utils/store/org';
import { supabase } from '../../../utils/functions/supabase';
let discussions = [];
dayjs.extend(relativeTime);
async function fetchCommunityQuestions(orgId) {
if (!orgId) return;
const { data, error } = await supabase
.from('community_question')
.select(
`
organization_id,
title,
votes,
created_at,
slug,
comments:community_answer(count),
author:organizationmember!community_question_author_id_fkey!inner(
profile!inner(fullname)
)
`
)
.eq('organization_id', orgId);
console.log('data', data);
console.log('error', error);
if (error) {
console.error('Error loading community', error);
return goto(`${currentOrgPath}`);
}
discussions =
data?.map((discussion) => ({
title: discussion.title,
slug: discussion.slug,
author: discussion?.author?.profile?.fullname,
comments: discussion.comments?.[0]?.count || 0,
votes: discussion.votes,
createdAt: dayjs(discussion.created_at).fromNow(true),
})) || [];
}
$: fetchCommunityQuestions($currentOrg.id);
</script>
<div
class="flex items-center justify-center lg:justify-start flex-wrap my-4 m-auto border-c rounded bg-gray-100 dark:bg-gray-700"
>
{#each discussions as discussion}
<div class="w-full flex border-bottom-c p-5">
<Vote value={discussion.votes} />
<div class="discussion-topic-author">
<h4>
<a
class="text-black dark:text-white"
rel="prefetch"
href="{$currentOrgPath}/community/{discussion.slug}"
>
{discussion.title}
</a>
</h4>
<span class="text-gray-600 dark:text-gray-100">
{discussion.author} asked {discussion.createdAt}
</span>
</div>
<Space />
<div class="flex items-center">
<AddComment20 />
<span class="ml-1">{discussion.comments}</span>
</div>
</div>
{:else}
<Box>
<CoursesEmptyIcon />
<h3 class="dark:text-white text-2xl my-5">No Questions asked</h3>
<p class="dark:text-white w-1/3 text-center">
Ask a question to the community
</p>
</Box>
{/each}
</div>
<style>
h4 {
font-size: 16px;
font-weight: 900;
word-break: break-word;
overflow-wrap: break-word;
margin: 0;
}
.discussion-topic-author {
margin-right: 20px;
}
.discussion-topic-author span {
font-size: 12px;
}
</style>
@@ -8,7 +8,7 @@
import { supabase } from '../../../utils/functions/supabase';
import { snackbarStore } from '../../Snackbar/store';
import { SNACKBAR_SEVERITY } from '../../Snackbar/constants';
import { currentOrg } from '../../../utils/store/org';
import { currentOrg, currentOrgPath } from '../../../utils/store/org';
import SectionTitle from '../SectionTitle.svelte';
let avatar;
@@ -74,7 +74,7 @@
}
function gotoSetting(pathname) {
goto(`/org/${$currentOrg.siteName}/settings${pathname}`);
goto(`${$currentOrgPath}/settings${pathname}`);
}
</script>
+51 -51
View File
@@ -1,6 +1,7 @@
<script>
import { stores } from '@sapper/app';
import Help from 'carbon-icons-svelte/lib/Help20';
import UserMultipleIcon from 'carbon-icons-svelte/lib/UserMultiple20';
import TextChip from '../../components/Chip/Text.svelte';
import OrgSelector from '../../components/OrgSelector/OrgSelector.svelte';
@@ -9,13 +10,35 @@
import SiteSettingsIcon from '../../components/Icons/SiteSettingsIcon.svelte';
import AudienceIcon from '../../components/Icons/AudienceIcon.svelte';
import Avatar from '../../components/Avatar/index.svelte';
import { currentOrg } from '../../utils/store/org';
import { currentOrg, currentOrgPath } from '../../utils/store/org';
import { profile } from '../../utils/store/user';
let orgSiteName = '';
let activeClass = 'bg-gray-200 dark:bg-gray-500';
let { page } = stores();
const menuItems = [
{
path: '',
label: 'Home',
},
{
path: '/courses',
label: 'Courses',
},
{
path: '/community',
label: 'Community',
},
{
path: '/site',
label: 'Site settings',
},
{
path: '/audience',
label: 'Audience',
},
];
function isActive(pagePath, itemPath) {
const pageLinkItems = pagePath.split('/');
const itemLinkItems = itemPath.split('/');
@@ -26,8 +49,6 @@
return pagePath.includes(itemPath);
}
$: orgSiteName = $currentOrg.siteName;
</script>
<aside class="root bg-gray-100 dark:bg-gray-700 h-full">
@@ -51,55 +72,34 @@
<OrgSelector />
<ul class="my-5">
<a href="/org/{orgSiteName}" class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
$page.path,
`/org/${orgSiteName}`
) && activeClass}"
>
<HomeIcon />
<p class="dark:text-white ml-2">Home</p>
</li>
</a>
<a href="/org/{orgSiteName}/courses" class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
$page.path,
`/org/${orgSiteName}/courses`
) && activeClass}"
>
<CourseIcon />
<p class="dark:text-white ml-2">Courses</p>
</li>
</a>
<a href="/org/{orgSiteName}/site" class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
$page.path,
`/org/${orgSiteName}/site`
) && activeClass}"
>
<SiteSettingsIcon />
<p class="dark:text-white ml-2">Site settings</p>
</li>
</a>
<a href="/org/{orgSiteName}/audience" class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
$page.path,
`/org/${orgSiteName}/audience`
) && activeClass}"
>
<AudienceIcon />
<p class="dark:text-white ml-2">Audience</p>
</li>
</a>
{#each menuItems as menuItem}
<a href="{$currentOrgPath}{menuItem.path}" class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
$page.path,
`${$currentOrgPath}${menuItem.path}`
) && activeClass}"
>
{#if menuItem.path === ''}
<HomeIcon />
{:else if menuItem.path === '/courses'}
<CourseIcon />
{:else if menuItem.path === '/site'}
<SiteSettingsIcon />
{:else if menuItem.path === '/community'}
<UserMultipleIcon class="carbon-icon" />
{:else if menuItem.path === '/audience'}
<AudienceIcon />
{/if}
<p class="dark:text-white ml-2">{menuItem.label}</p>
</li>
</a>
{/each}
</ul>
</div>
<span class="flex-grow" />
<ul class="my-5 pb-5 px-4">
<a href="/org" class="text-black">
<a href={$currentOrgPath} class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500"
>
@@ -107,11 +107,11 @@
<p class="dark:text-white ml-2">Help</p>
</li>
</a>
<a href="/org/{orgSiteName}/settings" class="text-black">
<a href="{$currentOrgPath}/settings" class="text-black">
<li
class="flex items-center py-3 px-4 mb-2 rounded hover:bg-gray-200 dark:hover:bg-gray-500 {isActive(
$page.path,
`/org/${orgSiteName}/settings`
`${$currentOrgPath}/settings`
) && activeClass}"
>
<Avatar