Files
sky_phone/frontend/src/stores/flare.ts
T
2026-08-17 01:30:41 +02:00

176 lines
5.6 KiB
TypeScript

import { defineStore } from 'pinia'
import type {
FlareBootstrap,
FlareMatch,
FlareMessage,
FlareOutgoingMessage,
FlareProfile,
FlareProfileDraft,
} from '@/types/flare'
import { nuiCall } from '@/utils/nui'
function hasValidProfilePhotos(
photoMediaIds: unknown,
): photoMediaIds is number[] {
return (
Array.isArray(photoMediaIds) &&
photoMediaIds.length >= 1 &&
photoMediaIds.length <= 6 &&
new Set(photoMediaIds).size === photoMediaIds.length &&
photoMediaIds.every((mediaId) => Number.isInteger(mediaId) && mediaId > 0)
)
}
export const useFlareStore = defineStore('flare', {
state: () => ({
activeMatchId: '' as string,
error: '' as string,
loading: false,
likes: [] as FlareBootstrap['likes'],
matches: [] as FlareMatch[],
messages: [] as FlareMessage[],
profile: null as FlareBootstrap['profile'],
sending: false,
suggestions: [] as FlareProfile[],
}),
actions: {
async bootstrap(): Promise<boolean> {
this.loading = true
const response = await nuiCall<FlareBootstrap>('flare:bootstrap')
this.loading = false
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success && response.data) {
this.applyBootstrap(response.data)
}
return response.success
},
async loadThread(matchId: string): Promise<boolean> {
this.activeMatchId = matchId
const response = await nuiCall<{ messages: FlareMessage[] }>(
'flare:thread',
{ matchId },
)
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success) {
this.messages = response.data?.messages ?? []
const match = this.matches.find((item) => item.id === matchId)
if (match) match.unread = 0
}
return response.success
},
async deleteProfile(): Promise<boolean> {
const response = await nuiCall('flare:delete-profile')
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success) this.reset()
return response.success
},
async saveProfile(draft: FlareProfileDraft): Promise<boolean> {
if (!hasValidProfilePhotos(draft.photoMediaIds)) {
this.error = 'invalid_profile_photos'
return false
}
const response = await nuiCall<FlareBootstrap>(
'flare:save-profile',
draft,
)
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success && response.data) {
this.applyBootstrap(response.data)
}
return response.success
},
async send(
matchId: string,
outgoing: FlareOutgoingMessage,
): Promise<boolean> {
this.sending = true
const response = await nuiCall<FlareMessage>('flare:send', {
matchId,
...outgoing,
})
this.sending = false
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success && response.data) {
this.messages.push(response.data)
const match = this.matches.find((item) => item.id === matchId)
if (match) {
match.lastMessage = response.data.body
match.lastMessageAt = response.data.createdAt
match.lastMessageType = response.data.messageType
}
}
return response.success
},
async swipe(
targetId: number,
choice: 'like' | 'pass' | 'superlike',
): Promise<FlareMatch | null> {
const response = await nuiCall<{ match: FlareMatch | null }>(
'flare:swipe',
{ choice, targetId },
)
this.error = response.success ? '' : (response.error ?? 'default')
if (!response.success) return null
this.suggestions = this.suggestions.filter(
(profile) => profile.id !== targetId,
)
this.likes = this.likes.filter((profile) => profile.id !== targetId)
const match = response.data?.match ?? null
if (match) {
this.matches = [
match,
...this.matches.filter((item) => item.id !== match.id),
]
}
return match
},
async rewind(): Promise<boolean> {
const response = await nuiCall<FlareBootstrap>('flare:rewind')
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success && response.data) this.applyBootstrap(response.data)
return response.success
},
async setDiscovery(enabled: boolean): Promise<boolean> {
const response = await nuiCall<FlareBootstrap>('flare:set-discovery', {
enabled,
})
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success && response.data) this.applyBootstrap(response.data)
return response.success
},
async unmatch(matchId: string): Promise<boolean> {
const response = await nuiCall<{ matches: FlareMatch[] }>(
'flare:unmatch',
{
matchId,
},
)
this.error = response.success ? '' : (response.error ?? 'default')
if (response.success) {
this.matches = response.data?.matches ?? []
this.messages = []
if (this.activeMatchId === matchId) this.activeMatchId = ''
}
return response.success
},
reset(error = ''): void {
this.activeMatchId = ''
this.error = error
this.loading = false
this.likes = []
this.matches = []
this.messages = []
this.profile = null
this.sending = false
this.suggestions = []
},
applyBootstrap(data: FlareBootstrap): void {
this.profile = data.profile
this.likes = data.likes
this.matches = data.matches
this.suggestions = data.suggestions
},
},
})