cos tam dziala
This commit is contained in:
4
front/.dockerignore
Normal file
4
front/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.DS_Store
|
||||
1
front/.gitignore
vendored
1
front/.gitignore
vendored
@@ -13,6 +13,7 @@ dist-ssr
|
||||
*.local
|
||||
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
19
front/Dockerfile
Normal file
19
front/Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
FROM oven/bun:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json bun.lockb* ./
|
||||
RUN bun install
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG VITE_API_URL
|
||||
ENV VITE_API_URL=$VITE_API_URL
|
||||
|
||||
RUN rm -f .env .env.*
|
||||
|
||||
RUN bun run build --mode production
|
||||
|
||||
EXPOSE 5173
|
||||
|
||||
CMD ["bun", "run", "preview", "--", "--host", "--port", "5173"]
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<div className="flex min-h-svh p-6">
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -25,13 +25,12 @@ export async function login(username: string, password: string): Promise<LoginRe
|
||||
}
|
||||
|
||||
export async function apiFetch(url: string, options: RequestInit = {}) {
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
return fetch(`${import.meta.env.VITE_API_URL}${url}`, {
|
||||
...options,
|
||||
credentials: "include",
|
||||
headers: {
|
||||
...options.headers,
|
||||
Authorization: token ? `Bearer ${token}` : "",
|
||||
// Authorization: token ? `Bearer ${token}` : "",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Outlet } from "react-router";
|
||||
|
||||
export default function AuthLayout() {
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { useAuth } from "@/providers/AuthProvider";
|
||||
import { Link, Outlet } from "react-router";
|
||||
import { type ReactNode } from "react";
|
||||
import { Link, Outlet, useLocation } from "react-router";
|
||||
|
||||
function Path({ url, children }: { url: string, children: ReactNode }) {
|
||||
const location = useLocation();
|
||||
let isActive = location.pathname === url;
|
||||
return (
|
||||
<Button
|
||||
variant={isActive ? "default" : "secondary"}
|
||||
asChild
|
||||
>
|
||||
<Link to={url}>{children}</Link>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export function MainLayout() {
|
||||
const { isAuthenticated, user, logout } = useAuth()
|
||||
@@ -20,7 +34,12 @@ export function MainLayout() {
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
<span className="text-lg font-semibold">papryk</span>
|
||||
|
||||
</Link>
|
||||
<Separator className="m-4" orientation="vertical" />
|
||||
{isAuthenticated && user &&
|
||||
<Path url="/video">video</Path>
|
||||
}
|
||||
|
||||
<div className="flex-1 flex justify-center">
|
||||
{/* Search
|
||||
@@ -36,19 +55,18 @@ export function MainLayout() {
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
{isAuthenticated && user &&
|
||||
<>
|
||||
<Link to="/video">Video</Link>
|
||||
<div>
|
||||
{user.username}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
<Button asChild size="sm">
|
||||
{isAuthenticated ?
|
||||
<Button onClick={logout}>Logout</Button>
|
||||
:
|
||||
{isAuthenticated ?
|
||||
<Button onClick={logout}>Logout</Button>
|
||||
:
|
||||
<Button asChild>
|
||||
<Link to="/auth/login">Login</Link>
|
||||
}
|
||||
</Button>
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { ReactNode } from "react";
|
||||
import { Link } from "react-router";
|
||||
|
||||
export function Home() {
|
||||
return (
|
||||
|
||||
@@ -28,7 +28,7 @@ export function LoginForm({
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [_error, setError] = useState<string | null>(null);
|
||||
|
||||
async function handleSubmit(e: FormEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -1,19 +1,38 @@
|
||||
import { apiFetch } from "@/api/auth";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function Video() {
|
||||
const [video, setVideo] = useState<string | null>(null);
|
||||
const getVideo = async () => {
|
||||
const res = await apiFetch("/protected/video");
|
||||
const txt = await res.text()
|
||||
setVideo(txt)
|
||||
|
||||
const refresh = async () => {
|
||||
await apiFetch(`/protected/refreshfiles`, {
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
useEffect(() => {
|
||||
getVideo()
|
||||
}, [])
|
||||
|
||||
const create = async () => {
|
||||
await apiFetch(`/protected/createclip`, {
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-1 flex-col gap-4 py-16">
|
||||
{video}
|
||||
<div>
|
||||
<Button
|
||||
onClick={() => { refresh() }}
|
||||
>Refresh</Button>
|
||||
<Button
|
||||
onClick={() => { create() }}
|
||||
>Create Clip</Button>
|
||||
</div>
|
||||
<video controls width="600">
|
||||
<source
|
||||
src={`${import.meta.env.VITE_API_URL}/protected/video`}
|
||||
type="video/mp4"
|
||||
/>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,20 +26,19 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
|
||||
// restore session
|
||||
useEffect(() => {
|
||||
const savedToken = localStorage.getItem("token");
|
||||
const savedUser = localStorage.getItem("user");
|
||||
|
||||
if (savedToken && savedUser) {
|
||||
setToken(savedToken);
|
||||
if (savedUser) {
|
||||
setUser(JSON.parse(savedUser));
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function login(username: string, password: string) {
|
||||
const res = await fetch("http://localhost:3000/auth/login", {
|
||||
const res = await fetch(`${import.meta.env.VITE_API_URL}/auth/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password })
|
||||
body: JSON.stringify({ username, password }),
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
@@ -51,7 +50,6 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
setToken(data.token);
|
||||
setUser(data.user);
|
||||
|
||||
localStorage.setItem("token", data.token);
|
||||
localStorage.setItem("user", JSON.stringify(data.user));
|
||||
}
|
||||
|
||||
@@ -59,7 +57,6 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
setUser(null);
|
||||
setToken(null);
|
||||
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("user");
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"baseUrl": ".",
|
||||
// "baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user