| import { storage } from '@/lib/storage' |
| import { useSocketContext } from '@/providers/socket-context' |
| import type { MusicSource, MyPlatformAuth, PlatformAuthStatus } from '@music-together/shared' |
| import { EVENTS, QR_STATUS } from '@music-together/shared' |
| import { useCallback, useEffect, useRef, useState } from 'react' |
| import { toast } from 'sonner' |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function useAuth() { |
| const { socket } = useSocketContext() |
| const [platformStatus, setPlatformStatus] = useState<PlatformAuthStatus[]>([]) |
| const [myStatus, setMyStatus] = useState<MyPlatformAuth[]>([]) |
| const [statusLoaded, setStatusLoaded] = useState(false) |
| const [qrData, setQrData] = useState<{ key: string; qrimg: string } | null>(null) |
| const [qrStatus, setQrStatus] = useState<{ status: number; message: string } | null>(null) |
| const [isQrLoading, setIsQrLoading] = useState(false) |
| const [isClaimingKugouConceptVip, setIsClaimingKugouConceptVip] = useState(false) |
| const [qrPlatform, setQrPlatform] = useState<MusicSource>('netease') |
|
|
| |
| const qrPlatformRef = useRef<MusicSource>(qrPlatform) |
| const qrKeyRef = useRef<string | null>(null) |
| const qrCompletedRef = useRef(false) |
|
|
| useEffect(() => { |
| const onStatusUpdate = (data: PlatformAuthStatus[]) => { |
| setPlatformStatus(data) |
| } |
|
|
| const onMyStatus = (data: MyPlatformAuth[]) => { |
| setMyStatus(data) |
| setStatusLoaded(true) |
| } |
|
|
| const onQrGenerated = (data: { key: string; qrimg: string }) => { |
| qrCompletedRef.current = false |
| qrKeyRef.current = data.key |
| setQrData(data) |
| setQrStatus({ status: 801, message: '等待扫码' }) |
| setIsQrLoading(false) |
| } |
|
|
| const onQrStatus = (data: { status: number; message: string; key?: string }) => { |
| if (qrCompletedRef.current) return |
| if (data.key && data.key !== qrKeyRef.current) return |
| if (data.status === QR_STATUS.SUCCESS || data.status === QR_STATUS.EXPIRED) { |
| qrCompletedRef.current = true |
| qrKeyRef.current = null |
| } |
| setQrStatus(data) |
| if (data.status === QR_STATUS.SUCCESS || data.status === QR_STATUS.EXPIRED) { |
| setIsQrLoading(false) |
| } |
| } |
|
|
| const onKugouConceptVipClaim = (data: { success: boolean; message: string }) => { |
| setIsClaimingKugouConceptVip(false) |
| if (data.success) toast.success(data.message) |
| else toast.error(data.message) |
| } |
|
|
| socket.on(EVENTS.AUTH_STATUS_UPDATE, onStatusUpdate) |
| socket.on(EVENTS.AUTH_MY_STATUS, onMyStatus) |
| socket.on(EVENTS.AUTH_QR_GENERATED, onQrGenerated) |
| socket.on(EVENTS.AUTH_QR_STATUS, onQrStatus) |
| socket.on(EVENTS.AUTH_CLAIM_KUGOU_CONCEPT_VIP_RESULT, onKugouConceptVipClaim) |
|
|
| |
| socket.emit(EVENTS.AUTH_GET_STATUS) |
|
|
| return () => { |
| socket.off(EVENTS.AUTH_STATUS_UPDATE, onStatusUpdate) |
| socket.off(EVENTS.AUTH_MY_STATUS, onMyStatus) |
| socket.off(EVENTS.AUTH_QR_GENERATED, onQrGenerated) |
| socket.off(EVENTS.AUTH_QR_STATUS, onQrStatus) |
| socket.off(EVENTS.AUTH_CLAIM_KUGOU_CONCEPT_VIP_RESULT, onKugouConceptVipClaim) |
| } |
| }, [socket]) |
|
|
| const requestQrCode = useCallback( |
| (platform: MusicSource) => { |
| setQrData(null) |
| qrCompletedRef.current = false |
| qrKeyRef.current = null |
| setQrStatus(null) |
| setIsQrLoading(true) |
| setQrPlatform(platform) |
| qrPlatformRef.current = platform |
| socket.emit(EVENTS.AUTH_REQUEST_QR, { platform }) |
| }, |
| [socket], |
| ) |
|
|
| const checkQrStatus = useCallback( |
| (key: string) => { |
| if (qrCompletedRef.current || qrKeyRef.current !== key) return |
| socket.emit(EVENTS.AUTH_CHECK_QR, { key, platform: qrPlatformRef.current }) |
| }, |
| [socket], |
| ) |
|
|
| const setCookie = useCallback( |
| (platform: MusicSource, cookie: string) => { |
| socket.emit(EVENTS.AUTH_SET_COOKIE, { platform, cookie }) |
| }, |
| [socket], |
| ) |
|
|
| const logout = useCallback( |
| (platform: MusicSource) => { |
| storage.removeAuthCookie(platform) |
| socket.emit(EVENTS.AUTH_LOGOUT, { platform }) |
| }, |
| [socket], |
| ) |
|
|
| const resetQr = useCallback(() => { |
| qrCompletedRef.current = true |
| qrKeyRef.current = null |
| setQrData(null) |
| setQrStatus(null) |
| setIsQrLoading(false) |
| }, []) |
|
|
| const claimKugouConceptVip = useCallback(() => { |
| if (isClaimingKugouConceptVip) return |
| setIsClaimingKugouConceptVip(true) |
| socket.emit(EVENTS.AUTH_CLAIM_KUGOU_CONCEPT_VIP) |
| }, [isClaimingKugouConceptVip, socket]) |
|
|
| return { |
| platformStatus, |
| myStatus, |
| statusLoaded, |
| qrData, |
| qrStatus, |
| qrPlatform, |
| isQrLoading, |
| requestQrCode, |
| checkQrStatus, |
| setCookie, |
| logout, |
| resetQr, |
| claimKugouConceptVip, |
| isClaimingKugouConceptVip, |
| } |
| } |
|
|