123
This commit is contained in:
@ -3,6 +3,11 @@ const nextConfig = {
|
|||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
eslint: { ignoreDuringBuilds: true },
|
eslint: { ignoreDuringBuilds: true },
|
||||||
transpilePackages: ['@coursecraft/shared'],
|
transpilePackages: ['@coursecraft/shared'],
|
||||||
|
// Проксируем /api на бэкенд — в браузере запросы идут на тот же хост, без localhost
|
||||||
|
async rewrites() {
|
||||||
|
const apiUrl = process.env.API_URL || 'http://127.0.0.1:3125';
|
||||||
|
return [{ source: '/api/:path*', destination: `${apiUrl}/api/:path*` }];
|
||||||
|
},
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
|
|||||||
29
apps/web/src/app/(auth)/forgot-password/page.tsx
Normal file
29
apps/web/src/app/(auth)/forgot-password/page.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Sparkles } from 'lucide-react';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ForgotPasswordPage() {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="text-center">
|
||||||
|
<Link href="/" className="flex items-center justify-center gap-2 mb-4">
|
||||||
|
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary">
|
||||||
|
<Sparkles className="h-5 w-5 text-primary-foreground" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xl font-bold">CourseCraft</span>
|
||||||
|
</Link>
|
||||||
|
<CardTitle>Восстановление пароля</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Функция восстановления пароля настраивается через Supabase (Email). Пока используйте вход через поставщика или обратитесь в поддержку.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="text-center">
|
||||||
|
<Link href="/login" className="text-primary hover:underline text-sm">
|
||||||
|
← Вернуться к входу
|
||||||
|
</Link>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
apps/web/src/app/(dashboard)/dashboard/search/page.tsx
Normal file
29
apps/web/src/app/(dashboard)/dashboard/search/page.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Search } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function DashboardSearchPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold">Поиск курсов</h1>
|
||||||
|
<p className="text-muted-foreground">Поиск по каталогу курсов (скоро)</p>
|
||||||
|
</div>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
<Search className="h-5 w-5" />
|
||||||
|
Поиск
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Здесь будет поиск по курсам через Meilisearch. Пока используйте раздел «Мои курсы».
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<p className="text-sm text-muted-foreground">Функция в разработке.</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
apps/web/src/app/icon.tsx
Normal file
28
apps/web/src/app/icon.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ImageResponse } from 'next/og';
|
||||||
|
|
||||||
|
export const size = { width: 32, height: 32 };
|
||||||
|
export const contentType = 'image/png';
|
||||||
|
|
||||||
|
export default function Icon() {
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
|
||||||
|
borderRadius: 8,
|
||||||
|
fontSize: 18,
|
||||||
|
color: 'white',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
C
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{ ...size }
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3125';
|
// В браузере — относительный URL (запросы на тот же хост, Next проксирует /api на бэкенд)
|
||||||
const API_URL = `${API_BASE}/api`;
|
const API_BASE =
|
||||||
|
typeof window !== 'undefined' ? '' : (process.env.API_URL || 'http://localhost:3125');
|
||||||
|
const API_URL = API_BASE ? `${API_BASE.replace(/\/$/, '')}/api` : '/api';
|
||||||
|
|
||||||
const STORAGE_KEY = 'coursecraft_api_token';
|
const STORAGE_KEY = 'coursecraft_api_token';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user