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:
@@ -1,15 +1,26 @@
|
||||
import { BaseApiWithErrors, classroomio } from '$lib/utils/services/api';
|
||||
import type {
|
||||
AssignAudienceCoursesRequest,
|
||||
DeleteTeamRequest,
|
||||
DomainRequestRequest,
|
||||
GetAudienceRequest,
|
||||
GetOrgPublicCoursesRequest,
|
||||
ImportAudienceRequest,
|
||||
InviteTeamRequest,
|
||||
OrgPublicCourses,
|
||||
OrganizationAudience,
|
||||
OrganizationTeamMembers
|
||||
OrganizationTeamMembers,
|
||||
ResendAudienceInviteRequest,
|
||||
RevokeAudienceInviteRequest
|
||||
} from '../utils/types';
|
||||
import type { TCreateOrganization, TGetOrganizations, TUpdateOrganization } from '@cio/utils/validation/organization';
|
||||
import { BaseApiWithErrors, classroomio } from '$lib/utils/services/api';
|
||||
import type {
|
||||
TAssignAudienceCourses,
|
||||
TAudienceInviteByEmail,
|
||||
TCreateOrganization,
|
||||
TGetOrganizations,
|
||||
TImportAudienceMembers,
|
||||
TUpdateOrganization
|
||||
} from '@cio/utils/validation/organization';
|
||||
import { ZCreateOrganization, ZUpdateOrganization } from '@cio/utils/validation/organization';
|
||||
import { currentOrg, orgs } from '$lib/utils/store/org';
|
||||
|
||||
@@ -370,6 +381,117 @@ class OrgApi extends BaseApiWithErrors {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports users into the organization as students
|
||||
*/
|
||||
async importAudienceMembers(data: TImportAudienceMembers) {
|
||||
console.log('importAudienceMembers', data);
|
||||
return this.execute<ImportAudienceRequest>({
|
||||
requestFn: () =>
|
||||
classroomio.organization.audience.import.$post({
|
||||
json: data
|
||||
}),
|
||||
logContext: 'importing audience members',
|
||||
onSuccess: (response) => {
|
||||
const d = response.data;
|
||||
snackbar.success(
|
||||
t.get('audience.import.snackbar_success', {
|
||||
imported: d.imported,
|
||||
skipped: d.skipped,
|
||||
emailsSent: d.emailsSent
|
||||
})
|
||||
);
|
||||
this.success = true;
|
||||
},
|
||||
onError: (result) => {
|
||||
if (typeof result === 'string') {
|
||||
snackbar.error(result);
|
||||
return;
|
||||
}
|
||||
if ('error' in result && 'field' in result) {
|
||||
this.errors[result.field as string] = result.error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns existing audience members to courses
|
||||
*/
|
||||
async assignAudienceToCourses(data: TAssignAudienceCourses) {
|
||||
return this.execute<AssignAudienceCoursesRequest>({
|
||||
requestFn: () =>
|
||||
classroomio.organization.audience['assign-courses'].$post({
|
||||
json: data
|
||||
}),
|
||||
logContext: 'assigning audience to courses',
|
||||
onSuccess: (response) => {
|
||||
const d = response.data;
|
||||
snackbar.success(
|
||||
t.get('audience.assign.snackbar_success', {
|
||||
assigned: d.assigned,
|
||||
alreadyEnrolled: d.alreadyEnrolled,
|
||||
emailsSent: d.emailsSent
|
||||
})
|
||||
);
|
||||
this.success = true;
|
||||
},
|
||||
onError: (result) => {
|
||||
if (typeof result === 'string') {
|
||||
snackbar.error(result);
|
||||
return;
|
||||
}
|
||||
if ('error' in result && 'field' in result) {
|
||||
this.errors[result.field as string] = result.error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async resendAudienceInvite(data: TAudienceInviteByEmail) {
|
||||
return this.execute<ResendAudienceInviteRequest>({
|
||||
requestFn: () =>
|
||||
classroomio.organization.audience['resend-invite'].$post({
|
||||
json: data
|
||||
}),
|
||||
logContext: 'resending audience invite',
|
||||
onSuccess: (response) => {
|
||||
if (response.data.emailSent) {
|
||||
snackbar.success('audience.invite.resend_snackbar_success');
|
||||
} else {
|
||||
snackbar.error('audience.invite.resend_snackbar_email_failed');
|
||||
}
|
||||
const orgId = get(currentOrg).id;
|
||||
if (orgId) this.getOrgAudience(orgId);
|
||||
},
|
||||
onError: (result) => {
|
||||
if (typeof result === 'string') {
|
||||
snackbar.error(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async revokeAudienceInvite(data: TAudienceInviteByEmail) {
|
||||
return this.execute<RevokeAudienceInviteRequest>({
|
||||
requestFn: () =>
|
||||
classroomio.organization.audience['revoke-invite'].$post({
|
||||
json: data
|
||||
}),
|
||||
logContext: 'revoking audience invite',
|
||||
onSuccess: () => {
|
||||
snackbar.success('audience.invite.revoke_snackbar_success');
|
||||
const orgId = get(currentOrg).id;
|
||||
if (orgId) this.getOrgAudience(orgId);
|
||||
},
|
||||
onError: (result) => {
|
||||
if (typeof result === 'string') {
|
||||
snackbar.error(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const orgApi = new OrgApi();
|
||||
|
||||
@@ -23,6 +23,8 @@ export type OrganizationAudienceSuccess = Extract<InferResponseType<GetAudienceR
|
||||
|
||||
export type OrganizationAudience = OrganizationAudienceSuccess['data'];
|
||||
|
||||
export type OrganizationAudienceMember = OrganizationAudience[number];
|
||||
|
||||
// Org Public Courses types
|
||||
export type GetOrgPublicCoursesRequest = typeof classroomio.organization.courses.public.$get;
|
||||
export type OrgPublicCoursesResponse = InferResponseType<GetOrgPublicCoursesRequest> | null;
|
||||
@@ -83,6 +85,20 @@ export type SsoDiscoveryResult = GetSsoDiscoverySuccess['data'];
|
||||
export type GetOrgSsoInfoSuccess = Extract<InferResponseType<GetOrgSsoInfoRequest>, { success: true }>;
|
||||
export type OrgSsoInfo = GetOrgSsoInfoSuccess['data'];
|
||||
|
||||
// Audience import types
|
||||
export type ImportAudienceRequest = (typeof classroomio.organization)['audience']['import']['$post'];
|
||||
export type ImportAudienceSuccess = Extract<InferResponseType<ImportAudienceRequest>, { success: true }>;
|
||||
export type ImportAudienceData = ImportAudienceSuccess['data'];
|
||||
|
||||
// Audience assign courses types
|
||||
export type AssignAudienceCoursesRequest = (typeof classroomio.organization)['audience']['assign-courses']['$post'];
|
||||
export type AssignAudienceCoursesSuccess = Extract<InferResponseType<AssignAudienceCoursesRequest>, { success: true }>;
|
||||
export type AssignAudienceCoursesData = AssignAudienceCoursesSuccess['data'];
|
||||
|
||||
// Audience invite actions
|
||||
export type ResendAudienceInviteRequest = (typeof classroomio.organization)['audience']['resend-invite']['$post'];
|
||||
export type RevokeAudienceInviteRequest = (typeof classroomio.organization)['audience']['revoke-invite']['$post'];
|
||||
|
||||
// Token auth types
|
||||
export type CreateTokenAuthRequest = (typeof classroomio.organization)['token-auth']['$post'];
|
||||
export type GetTokenAuthRequest = (typeof classroomio.organization)['token-auth']['$get'];
|
||||
|
||||
Reference in New Issue
Block a user