Add team roles and content management updates

This commit is contained in:
AzuTear
2026-06-25 19:52:46 +02:00
parent 54293f4c45
commit 693769e5a8
126 changed files with 6966 additions and 738 deletions
+99 -6
View File
@@ -2,10 +2,32 @@ import { defineStore } from 'pinia'
import { AUTH_TOKEN_KEY, api } from '../lib/api'
import { ApiRequestError } from '../lib/http'
import type { AuthSession, DemoLoginPayload, LoginPayload } from '../types/awards'
import type {
AuthSession,
BindTeamTwitchPayload,
ChangePasswordPayload,
DemoLoginPayload,
LoginPayload,
TeamLoginPayload,
TeamTwitchLoginPayload,
TwitchAuthorizePayload,
} from '../types/awards'
const adminAccessRoles = new Set(['content_admin', 'admin', 'owner'])
const adminWorkspaceRoles = new Set(['admin', 'owner'])
const adminAccessRoles = new Set(['member', 'reviewer', 'organization_team', 'content_admin', 'admin', 'owner', 'creator'])
const contentManageRoles = new Set(['content_admin', 'admin', 'owner', 'creator'])
const adminWorkspaceRoles = new Set(['admin', 'owner', 'creator'])
const adminWorkspacePermissions = new Set([
'dashboard',
'years',
'nominations',
'categories',
'candidates',
'clips',
'risk',
'audit',
'analytics',
'winners',
])
function readStoredToken() {
if (typeof window === 'undefined') return null
@@ -32,10 +54,15 @@ export const useAuthStore = defineStore('auth', {
isLoggedIn: (state) => Boolean(state.session),
isAdmin: (state) => adminAccessRoles.has(state.session?.role ?? ''),
canAccessAdmin: (state) => adminAccessRoles.has(state.session?.role ?? ''),
canManageContent: (state) => adminAccessRoles.has(state.session?.role ?? ''),
canManageAdminWorkspace: (state) => adminWorkspaceRoles.has(state.session?.role ?? ''),
canManageOperationalSettings: (state) => state.session?.role === 'owner',
canManageContent: (state) => contentManageRoles.has(state.session?.role ?? '') || (state.session?.permissionKeys ?? []).includes('content'),
canManageAdminWorkspace: (state) => adminWorkspaceRoles.has(state.session?.role ?? '') || (state.session?.permissionKeys ?? []).some((key) => adminWorkspacePermissions.has(key)),
canManageOperationalSettings: (state) => state.session?.role === 'owner' || state.session?.role === 'creator',
canManageTeam: (state) => (state.session?.permissionKeys ?? []).includes('team'),
hasPermission: (state) => (permissionKey: string) => (state.session?.permissionKeys ?? []).includes(permissionKey),
isOwner: (state) => state.session?.role === 'owner',
isCreator: (state) => state.session?.role === 'creator',
isOwnerOrCreator: (state) => state.session?.role === 'owner' || state.session?.role === 'creator',
isTeamSession: (state) => Boolean(state.session?.teamLogin),
},
actions: {
async hydrate() {
@@ -75,6 +102,72 @@ export const useAuthStore = defineStore('auth', {
this.loading = false
}
},
async teamLogin(payload: TeamLoginPayload) {
this.loading = true
try {
const session = await api.teamLogin(payload)
this.session = session
writeStoredToken(session.sessionToken)
} finally {
this.loading = false
}
},
async teamTwitchLogin(payload: TeamTwitchLoginPayload) {
this.loading = true
try {
const session = await api.teamTwitchLogin(payload)
this.session = session
writeStoredToken(session.sessionToken)
} finally {
this.loading = false
}
},
async changePassword(payload: ChangePasswordPayload) {
this.loading = true
try {
const session = await api.changePassword(payload)
this.session = session
writeStoredToken(session.sessionToken)
} finally {
this.loading = false
}
},
async bindTeamTwitch(payload: BindTeamTwitchPayload) {
this.loading = true
try {
const session = await api.bindTeamTwitch(payload)
this.session = session
writeStoredToken(session.sessionToken)
} finally {
this.loading = false
}
},
async startTwitchAuthorization(payload: Omit<TwitchAuthorizePayload, 'frontendOrigin'>) {
this.loading = true
try {
const response = await api.startTwitchAuthorization({
...payload,
frontendOrigin: window.location.origin,
})
window.location.assign(response.authorizationUrl)
} finally {
this.loading = false
}
},
async completeOAuthSession(sessionToken: string) {
this.loading = true
try {
writeStoredToken(sessionToken)
this.session = await api.getSession()
this.hydrated = true
} catch (error) {
writeStoredToken(null)
this.session = null
throw error
} finally {
this.loading = false
}
},
async logout() {
this.loading = true
try {
+5 -1
View File
@@ -45,7 +45,11 @@ export const useAwardsStore = defineStore('awards', {
try {
this.overview = await api.getOverview()
this.categories = await api.getSeasonCategories(this.overview.year)
this.archive = await api.getWinnerArchive(this.overview.winnersPreview[0]?.year ?? this.overview.year - 1)
const overviewArchiveYears = this.overview.archiveYears ?? []
const initialArchiveYear = overviewArchiveYears[0]?.year
?? this.overview.winnersPreview[0]?.year
?? this.overview.year - 1
this.archive = await api.getWinnerArchive(initialArchiveYear)
this.apiMode = 'api'
} catch (error) {
this.apiMode = 'fallback'
+4
View File
@@ -29,6 +29,7 @@ export function createEmptyOverview(): OverviewResponse {
timeline: [],
featuredCategories: [],
winnersPreview: [],
archiveYears: [],
siteContent: {
hostDisplayName: '',
hostTagline: '',
@@ -116,8 +117,11 @@ export function createEmptyAdminSiteSettings(): AdminSiteSettingsResponse {
privacyPolicyUpdatedBy: null,
privacyPolicyUpdatedAt: null,
imprintUrl: '',
imprintContent: '',
contactUrl: '',
contactContent: '',
sponsorsUrl: '',
sponsorsContent: '',
socialLinks: [],
faq: [],
}