feat: implement authentication context and hooks for user management

- Add AuthContext to manage user authentication state and token storage.
- Create hooks for login, registration, and logout functionalities.
- Implement dashboard layout with authentication check and loading state.
- Enhance dashboard page with channel management features including create, edit, and delete channels.
- Integrate API calls for channel operations and current broadcast retrieval.
- Add stream URL resolution via server-side API route to handle redirects.
- Update TV page to utilize new hooks for channel and broadcast management.
- Refactor components for better organization and user experience.
- Update application metadata for improved branding.
This commit is contained in:
2026-03-11 19:32:49 +01:00
parent 01108aa23e
commit 8d8d320a02
22 changed files with 2118 additions and 173 deletions

View File

@@ -0,0 +1,102 @@
"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "@/lib/api";
import { useAuthContext } from "@/context/auth-context";
import type { CreateChannelRequest, UpdateChannelRequest } from "@/lib/types";
export function useChannels() {
const { token } = useAuthContext();
return useQuery({
queryKey: ["channels"],
queryFn: () => api.channels.list(token!),
enabled: !!token,
});
}
export function useChannel(id: string) {
const { token } = useAuthContext();
return useQuery({
queryKey: ["channel", id],
queryFn: () => api.channels.get(id, token!),
enabled: !!token && !!id,
});
}
export function useCreateChannel() {
const { token } = useAuthContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateChannelRequest) =>
api.channels.create(data, token!),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["channels"] });
},
});
}
export function useUpdateChannel() {
const { token } = useAuthContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateChannelRequest }) =>
api.channels.update(id, data, token!),
onSuccess: (updated) => {
queryClient.invalidateQueries({ queryKey: ["channels"] });
queryClient.invalidateQueries({ queryKey: ["channel", updated.id] });
},
});
}
export function useDeleteChannel() {
const { token } = useAuthContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => api.channels.delete(id, token!),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["channels"] });
},
});
}
export function useGenerateSchedule() {
const { token } = useAuthContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: (channelId: string) =>
api.schedule.generate(channelId, token!),
onSuccess: (_, channelId) => {
queryClient.invalidateQueries({ queryKey: ["schedule", channelId] });
},
});
}
export function useActiveSchedule(channelId: string) {
const { token } = useAuthContext();
return useQuery({
queryKey: ["schedule", channelId],
queryFn: () => api.schedule.getActive(channelId, token!),
enabled: !!token && !!channelId,
retry: false,
});
}
export function useCurrentBroadcast(channelId: string) {
const { token } = useAuthContext();
return useQuery({
queryKey: ["broadcast", channelId],
queryFn: () => api.schedule.getCurrentBroadcast(channelId, token!),
enabled: !!token && !!channelId,
refetchInterval: 30_000,
retry: false,
});
}
export function useEpg(channelId: string, from?: string, until?: string) {
const { token } = useAuthContext();
return useQuery({
queryKey: ["epg", channelId, from, until],
queryFn: () => api.schedule.getEpg(channelId, token!, from, until),
enabled: !!token && !!channelId,
});
}