Enhance audience management features with new components and API integrations

- Added `AssignCoursesModal`, `AudienceMemberRow`, `AudienceTable`, and related components for improved audience management UI.
- Implemented audience invite actions including resend and revoke functionality.
- Updated audience API to support importing members and assigning courses.
- Refactored audience data handling to include status and invite management.
- Improved overall user experience with pagination and selection features in the audience table.
This commit is contained in:
Rotimi Best
2026-03-22 18:42:23 +01:00
parent e9c4082f89
commit 3919ff6c2f
157 changed files with 13183 additions and 872 deletions
@@ -0,0 +1,5 @@
import MultiSelectList from './multi-select-list.svelte';
export { MultiSelectList };
export { MultiSelectList as default };
export type { MultiSelectListItem } from './types';
@@ -0,0 +1,49 @@
<script lang="ts">
import { CheckboxField } from '../checkbox-field';
import { cn } from '../../tools';
import type { MultiSelectListItem } from './types';
interface Props {
heading: string;
emptyMessage: string;
items: MultiSelectListItem[];
isSelected: (id: string) => boolean;
onToggle: (id: string) => void;
/** Prefix for each row's checkbox `name` (e.g. `assign-course` → `assign-course-<id>`). */
namePrefix?: string;
class?: string;
/** Extra classes for the scrollable list container (`data-slot="multi-select-list-items"`). */
listClass?: string;
}
let {
heading,
emptyMessage,
items,
isSelected,
onToggle,
namePrefix = 'multi-select',
class: className,
listClass
}: Props = $props();
</script>
<div data-slot="multi-select-list" class={cn('ui:border-border space-y-3 rounded-md border', className)}>
<p class="ui:border-border border-b px-2 py-2 text-sm font-medium">
{heading} ({items.length})
</p>
{#if items.length === 0}
<p class="ui:text-muted-foreground px-2 pb-2 text-sm">{emptyMessage}</p>
{:else}
<div data-slot="multi-select-list-items" class={cn('max-h-60 space-y-2 overflow-y-auto px-2 pb-2', listClass)}>
{#each items as item (item.id)}
<CheckboxField
name={`${namePrefix}-${item.id}`}
label={item.label || item.id}
checked={isSelected(item.id)}
onclick={() => onToggle(item.id)}
/>
{/each}
</div>
{/if}
</div>
@@ -0,0 +1 @@
export type MultiSelectListItem = { id: string; label: string };