Initial commit
This commit is contained in:
2
frontend/.env
Normal file
2
frontend/.env
Normal file
@@ -0,0 +1,2 @@
|
||||
REACT_APP_API_URL=http://localhost:8000
|
||||
REACT_APP_WS_URL=ws://localhost:8000
|
||||
39
frontend/package.json
Normal file
39
frontend/package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "video-streaming-frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.10.0",
|
||||
"@types/react": "^18.2.45",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"axios": "^1.6.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.21.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
14
frontend/public/index.html
Normal file
14
frontend/public/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Платформа для стриминга видео" />
|
||||
<title>Video Streaming</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
31
frontend/src/api.ts
Normal file
31
frontend/src/api.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: API_URL,
|
||||
});
|
||||
|
||||
api.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
export const authAPI = {
|
||||
getLoginUrl: () => api.get('/auth/login'),
|
||||
callback: (code: string) => api.post('/auth/callback', { code }),
|
||||
getMe: () => api.get('/me'),
|
||||
};
|
||||
|
||||
export const streamAPI = {
|
||||
getStreams: () => api.get('/streams'),
|
||||
getStream: (id: string) => api.get(`/streams/${id}`),
|
||||
createStream: (data: { title: string; description?: string }) =>
|
||||
api.post('/streams', data),
|
||||
endStream: (id: string) => api.delete(`/streams/${id}`),
|
||||
};
|
||||
|
||||
export default api;
|
||||
0
frontend/src/components/StreamBroadcaster.tsx
Normal file
0
frontend/src/components/StreamBroadcaster.tsx
Normal file
0
frontend/src/components/StreamPlayer.tsx
Normal file
0
frontend/src/components/StreamPlayer.tsx
Normal file
52
frontend/src/context/AuthContext.tsx
Normal file
52
frontend/src/context/AuthContext.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
import { User, AuthContextType } from '../types';
|
||||
import { authAPI } from '../api';
|
||||
|
||||
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
||||
|
||||
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [token, setToken] = useState<string | null>(localStorage.getItem('token'));
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
authAPI.getMe()
|
||||
.then(response => setUser(response.data))
|
||||
.catch(() => {
|
||||
localStorage.removeItem('token');
|
||||
setToken(null);
|
||||
});
|
||||
}
|
||||
}, [token]);
|
||||
|
||||
const login = async () => {
|
||||
const response = await authAPI.getLoginUrl();
|
||||
window.location.href = response.data.auth_url;
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem('token');
|
||||
setToken(null);
|
||||
setUser(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{
|
||||
user,
|
||||
token,
|
||||
login,
|
||||
logout,
|
||||
isAuthenticated: !!token
|
||||
}}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error('useAuth must be used within AuthProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
25
frontend/src/types.ts
Normal file
25
frontend/src/types.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
picture?: string;
|
||||
}
|
||||
|
||||
export interface Stream {
|
||||
id: string;
|
||||
user_id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
is_live: boolean;
|
||||
viewer_count: number;
|
||||
created_at: string;
|
||||
thumbnail?: string;
|
||||
}
|
||||
|
||||
export interface AuthContextType {
|
||||
user: User | null;
|
||||
token: string | null;
|
||||
login: () => void;
|
||||
logout: () => void;
|
||||
isAuthenticated: boolean;
|
||||
}
|
||||
20
frontend/tsconfig.json
Normal file
20
frontend/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user