diff --git a/AI_GUIDE.md b/AI_GUIDE.md index a98ca18..765d69c 100644 --- a/AI_GUIDE.md +++ b/AI_GUIDE.md @@ -164,7 +164,7 @@ Add this comment at the top of every new file: * Created by: Chandika Nurdiansyah (chandika@skatsa.com) * Date: [current date] * Purpose: [brief description of file purpose] - * Part of: SDI Super App for PT Skatsa Data Integra + * Part of: PT Skatsa Data Integra */ ``` @@ -175,7 +175,7 @@ For modified files, add this comment above your changes: * Modified by: Chandika Nurdiansyah (chandika@skatsa.com) * Date: [current date] * Changes: [brief description of changes] - * Part of: SDI Super App for PT Skatsa Data Integra + * Part of: PT Skatsa Data Integra */ ``` @@ -209,7 +209,7 @@ For modified files, add this comment above your changes: - **Responsive Design**: Mobile-first approach - **Error Handling**: Comprehensive error messages and recovery - **Loading States**: Smooth transitions and visual feedback -- **Component Reuse**: Maximize use of existing Common components (AppTable, AppForm, etc.) before creating custom components +- **Component Reuse**: Maximize use of existing Common components before creating custom components - **Component Index Files**: ALWAYS include `index.ts` file in `/components/` and all subdirectories to export components for clean imports - **Mandatory Component Usage**: - ALL edit pages MUST use AppForm component @@ -431,7 +431,6 @@ export { default as ActionButton } from "./index"; - User management, roles, authorization, app management - Requires admin-level permissions - **Business Applications**: `/app/(app)` - Business operations - - Finance & Accounting, future business modules - Requires role-based permissions per module diff --git a/README.md b/README.md index e215bc4..8a57d61 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,104 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# kreatiVortex - Platform Pembelajaran Tari Online -## Getting Started +Platform pembelajaran tari online yang menghubungkan pendidik, calon pendidik, dan masyarakat umum untuk melestarikan dan mempelajari tari tradisional Indonesia. -First, run the development server: +## 🌟 Fitur Utama +### 🎭 Manajemen Konten Pembelajaran +- **Video Pembelajaran**: Upload dan tonton video tutorial tari (mendukung YouTube dan file lokal) +- **Materi Teori**: Akses materi sejarah, filosofi, dan kostum tari +- **Materi Praktik**: Panduan langkah demi langkah gerakan tari +- **Template Makalah**: Download template tugas dan panduan observasi + +### 🏫 Manajemen Kelas +- **Sistem Kelas**: Pendidik dapat membuat kelas dan mengelola siswa +- **Jadwal & Pengumuman**: Informasi terupdate mengenai jadwal latihan +- **Penugasan**: Sistem pemberian dan pengumpulan tugas terintegrasi + +### 💬 Kolaborasi & Komunitas +- **Forum Diskusi**: Diskusi umum dan spesifik per kelas +- **Komentar**: Interaksi pada video dan postingan forum +- **Peran Pengguna**: Sistem 4 peran (Administrator, Pendidik, Calon Pendidik, Umum) + +## 🚀 Teknologi + +- **Framework**: Next.js 16 (App Router) +- **Bahasa**: TypeScript +- **Database**: PostgreSQL dengan Prisma ORM +- **Auth**: Better Auth +- **Styling**: Tailwind CSS +- **UI Components**: Custom components (Glassmorphism design) + +## 🛠️ Instalasi & Menjalankan Project + +1. **Clone repository** +```bash +git clone https://github.com/yourusername/kreati-vortex.git +cd kreati-vortex +``` + +2. **Install dependencies** +```bash +bun install +``` + +3. **Setup Database** +Pastikan PostgreSQL sudah berjalan, lalu konfigurasi `.env`: +```env +DATABASE_URL="postgresql://user:password@localhost:5432/kreativortex?schema=public" +``` + +Jalankan migrasi database: +```bash +bun prisma db push +``` + +4. **Jalankan Development Server** ```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or bun dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +Buka [http://localhost:3000](http://localhost:3000) di browser Anda. -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +## 📂 Struktur Project -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +``` +app/ +├── (app)/ # Halaman aplikasi (protected) +│ └── dashboard/ # Dashboard utama +│ ├── assignments/ # Manajemen tugas +│ ├── classes/ # Manajemen kelas +│ ├── forum/ # Forum diskusi +│ ├── videos/ # Manajemen video +│ ├── teori/ # Materi teori +│ ├── praktik/ # Materi praktik +│ └── template-makalah/ # Download template +├── api/ # API Endpoints +│ ├── auth/ # Autentikasi +│ ├── videos/ # CRUD Video +│ ├── forums/ # CRUD Forum +│ ├── classes/ # CRUD Kelas +│ └── assignments/ # CRUD Tugas +└── auth/ # Halaman autentikasi (public) + ├── signin/ # Halaman login + └── signup/ # Halaman registrasi -## Learn More +components/ +├── ActionButton/ # Komponen tombol +├── Common/ # Komponen umum (Layout, Table, Form) +└── Forms/ # Komponen form spesifik -To learn more about Next.js, take a look at the following resources: +prisma/ +└── schema.prisma # Skema database +``` -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +## 🔐 Hak Akses (Role) -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +1. **Administrator**: Akses penuh ke seluruh sistem +2. **Pendidik**: Manajemen kelas, video, tugas, dan forum +3. **Calon Pendidik**: Mengikuti kelas, akses materi, upload tugas +4. **Umum**: Akses materi publik dan forum umum -## Deploy on Vercel +## 📝 Lisensi -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +[MIT](LICENSE) \ No newline at end of file diff --git a/TODO-kreatiVortex-platform.md b/TODO-kreatiVortex-platform.md deleted file mode 100644 index 4162238..0000000 --- a/TODO-kreatiVortex-platform.md +++ /dev/null @@ -1,163 +0,0 @@ -# TODO: kreatiVortex - Platform Pembelajaran Tari Online - -**Created by:** AI Assistant -**Date:** 2025-11-28 -**Purpose:** Complete development of kreatiVortex online dance learning platform with user management, video content, forums, and assignment system - -## 📋 Task Breakdown - -### Phase 1: Project Setup & Foundation - -- [x] Initialize Next.js 16+ project with TypeScript -- [x] Install and configure Better Auth framework -- [x] Set up Prisma ORM with database connection -- [ ] Configure project structure following AI_GUIDE.md patterns -- [ ] Set up ESLint, TypeScript configuration -- [ ] Create basic layout and routing structure - -### Phase 2: Database Schema & Models - -- [ ] Create User model with role-based access (Administrator, Pendidik, Calon Pendidik, Umum) -- [ ] Create Class/Instansi model for class management -- [ ] Create Video model with YouTube/local file support -- [ ] Create Forum model (General and Class-based) -- [ ] Create Assignment model with Word document support -- [ ] Create Comment model for video and forum interactions -- [ ] Add audit fields (createdBy, createdAt, updatedAt, updatedBy) -- [ ] Generate Prisma client and push schema to database -- [ ] Create seed data for initial users and roles - -### Phase 3: Authentication & User Management - -- [ ] Implement Better Auth configuration with role-based access -- [ ] Create landing page with Login, Register, Mulai Sekarang buttons -- [ ] Implement basic registration (Name, Email, Password, Password Confirmation) -- [ ] Create role upgrade forms (Pendidik and Calon Pendidik registration) -- [ ] Implement login/logout functionality -- [ ] Create user dashboard with role-specific options -- [ ] Add authorization middleware for protected routes - -### Phase 4: Core UI Components & Layout - -- [ ] Create main layout with navigation (Beranda, Teori, Praktik, Template Makalah) -- [ ] Implement Navy (#000080), Gray (#A9A9A9), White (#FFFFFF) color scheme -- [ ] Add background.jpg with overlay effect -- [ ] Create AppDataView component for data tables -- [ ] Create AppForm component for forms -- [ ] Create ActionButton component for buttons -- [ ] Ensure responsive design and mobile-first approach -- [ ] Add skeleton loading states - -### Phase 5: Video Management System - -- [ ] Create video upload page with file/YouTube options -- [ ] Implement YouTube URL validation and embedding -- [ ] Create video player page with comments -- [ ] Implement Beranda page showing community videos -- [ ] Create video filtering (by uploader, latest, popular) -- [ ] Add administrator-specific video placement options -- [ ] Implement video storage and compression for local files - -### Phase 6: Learning Content Management - -- [ ] Create Teori page for theoretical content -- [ ] Create Praktik page for practical content -- [ ] Implement administrator-only content placement for Teori/Praktik -- [ ] Create Template Makalah page for document downloads -- [ ] Add content categorization and organization -- [ ] Implement content suggestion system for Pendidik - -### Phase 7: Forum & Collaboration System - -- [ ] Create Forum Umum for all users -- [ ] Create Forum Group/Kelas for Pendidik and Calon Pendidik -- [ ] Implement thread creation and reply functionality -- [ ] Add forum moderation features -- [ ] Create class-based discussion organization -- [ ] Implement rich text editor for forum posts - -### Phase 8: Assignment & Document Management - -- [ ] Create assignment creation system for Pendidik -- [ ] Implement Word document upload for Calon Pendidik -- [ ] Create revision system with document comparison -- [ ] Add assignment tracking and status management -- [ ] Implement notification system for assignments -- [ ] Create document download and management features - -### Phase 9: Class Management System - -- [ ] Create class creation and management for Pendidik -- [ ] Implement class joining system for Calon Pendidik -- [ ] Add class member management -- [ ] Create class-specific content organization -- [ ] Implement class analytics and reporting -- [ ] Add class approval workflows - -### Phase 10: API Development - -- [ ] Create user management API endpoints -- [ ] Create video CRUD API endpoints -- [ ] Create forum API endpoints -- [ ] Create assignment API endpoints -- [ ] Create class management API endpoints -- [ ] Implement proper error handling and validation -- [ ] Add authentication and authorization checks -- [ ] Create TypeScript interfaces for API responses - -### Phase 11: Testing & Quality Assurance - -- [ ] Run ESLint (0 errors, 0 warnings) -- [ ] Run TypeScript type checking (0 errors) -- [ ] Perform build test (successful compilation) -- [ ] Test authentication flows end-to-end -- [ ] Test CRUD operations functionality -- [ ] Test permission matrix and role-based access -- [ ] Test video upload and playback functionality -- [ ] Test forum and assignment workflows -- [ ] Perform responsive design testing -- [ ] Test with MCP Server for browser automation - -### Phase 12: Documentation & Deployment - -- [ ] Update README.md with project structure and features -- [ ] Document API endpoints and usage -- [ ] Create component documentation -- [ ] Add deployment configuration -- [ ] Perform final security review -- [ ] Optimize performance and loading times - -## 🎯 Expected Outcomes - -- [ ] Complete kreatiVortex platform with all required features -- [ ] Four-tier user role system with proper access control -- [ ] Video management with local and YouTube support -- [ ] Forum system for community and class discussions -- [ ] Assignment system with Word document support -- [ ] Class management and organization -- [ ] Responsive design with Navy/Gray/White color scheme -- [ ] Better Auth integration for secure authentication -- [ ] Comprehensive API with proper error handling -- [ ] Mobile-responsive and accessible design - -## ⚠️ Risks & Considerations - -- **Video Storage**: Local file storage may require significant server space and compression -- **YouTube Integration**: Direct URL embedding without API may have limitations -- **Document Processing**: Word document handling requires proper file type validation -- **Role Complexity**: Four-tier role system requires careful permission management -- **Performance**: Video streaming and large file uploads may impact performance -- **Security**: User data (especially NIM and documents) requires proper encryption -- **Scalability**: System must handle growing number of users, videos, and documents - -## 🔄 Dependencies - -- **Next.js 16+**: Core framework for the application -- **Better Auth**: Authentication and authorization framework -- **Prisma ORM**: Database management and migrations -- **TypeScript**: Type safety and development experience -- **shadcn/ui**: UI component library -- **Database**: PostgreSQL or MySQL for data storage -- **File Storage**: Local storage or cloud storage for videos and documents -- **YouTube API**: Optional for enhanced YouTube integration -- **Rich Text Editor**: For forum posts and content creation \ No newline at end of file diff --git a/app/(app)/dashboard/layout.tsx b/app/(app)/dashboard/layout.tsx deleted file mode 100644 index 5885308..0000000 --- a/app/(app)/dashboard/layout.tsx +++ /dev/null @@ -1,170 +0,0 @@ -/** - * File: layout.tsx - * Created by: AI Assistant - * Date: 2025-11-29 - * Purpose: Dashboard layout for kreatiVortex platform - * Part of: kreatiVortex - Platform Pembelajaran Tari Online - */ - -import Link from 'next/link'; -import { ReactNode } from 'react'; - -export default function DashboardLayout({ - children, -}: { - children: ReactNode; -}) { - return ( -
- {/* Background overlay */} -
- -
- {/* Sidebar */} -
-
- {/* Logo */} - -
- kV -
- - kreatiVortex - - -
- - {/* Navigation */} - -
- - {/* Main content */} -
- {/* Top bar */} -
-
-

- Dashboard -

- -
- {/* Notifications */} - - - {/* Profile */} -
-
-

John Doe

-

Calon Pendidik

-
-
- JD -
-
-
-
-
- - {/* Page content */} -
- {children} -
-
-
-
- ); -} \ No newline at end of file diff --git a/app/(app)/dashboard/page.tsx b/app/(app)/dashboard/page.tsx deleted file mode 100644 index ce86dfb..0000000 --- a/app/(app)/dashboard/page.tsx +++ /dev/null @@ -1,130 +0,0 @@ -/** - * File: page.tsx - * Created by: AI Assistant - * Date: 2025-11-29 - * Purpose: Dashboard page for kreatiVortex platform - * Part of: kreatiVortex - Platform Pembelajaran Tari Online - */ - -export default function Dashboard() { - return ( -
-
-

- Selamat Datang di kreatiVortex! -

-

- Platform pembelajaran tari tradisional Indonesia -

-
- - {/* Stats Cards */} -
-
-
-
-

Total Video

-

24

-
-
- - - -
-
-
- -
-
-
-

Kelas Aktif

-

3

-
-
- - - -
-
-
- -
-
-
-

Tugas Selesai

-

12

-
-
- - - -
-
-
- -
-
-
-

Forum Post

-

48

-
-
- - - -
-
-
-
- - {/* Recent Activity */} -
- {/* Recent Videos */} -
-

Video Terbaru

-
-
-
- - - -
-
-

Tari Piring - Dasar

-

2 jam yang lalu

-
-
-
-
- - - -
-
-

Tari Saman - Gerakan Tangan

-

5 jam yang lalu

-
-
-
-
- - {/* Recent Forum Posts */} -
-

Diskusi Terbaru

-
-
-

Tips untuk pemula Tari Piring

-

Saya ingin berbagi beberapa tips untuk yang baru mulai belajar...

-

Oleh Sarah Pendidik • 1 jam yang lalu

-
-
-

Costum untuk pertunjukan

-

Apakah ada saran untuk costum yang tepat untuk pertunjukan tari...

-

Oleh Budi Student • 3 jam yang lalu

-
-
-
-
-
- ); -} \ No newline at end of file diff --git a/app/[locale]/(app)/dashboard/assignments/[id]/page.tsx b/app/[locale]/(app)/dashboard/assignments/[id]/page.tsx new file mode 100644 index 0000000..1ec06dd --- /dev/null +++ b/app/[locale]/(app)/dashboard/assignments/[id]/page.tsx @@ -0,0 +1,104 @@ +/** + * File: page.tsx + * Created by: AI Assistant + * Date: 2025-11-29 + * Purpose: Assignment detail page for kreatiVortex platform + * Part of: kreatiVortex - Platform Pembelajaran Tari Online + */ + +'use client'; + +import Link from 'next/link'; +import ActionButton from '@/components/ActionButton'; + +export default function AssignmentDetailPage() { + const assignment = { + id: 1, + title: 'Analisis Gerakan Tari Piring', + description: 'Buatlah makalah analisis mengenai teknik dasar gerakan Tari Piring. Fokuskan analisis pada: 1. Teknik memegang piring, 2. Koordinasi gerakan tangan dan kaki, 3. Pola lantai dasar. Panjang makalah minimal 500 kata.', + class: 'Tari Tradisional Indonesia 101', + educator: 'Sarah Pendidik', + dueDate: '2025-12-05T23:59:00Z', + maxScore: 100, + status: 'Belum Diserahkan', + mySubmission: null, + }; + + return ( +
+
+ + + + + Kembali ke Daftar Tugas + +
+ +
+ {/* Assignment Details */} +
+
+
+ + {assignment.class} + + + Oleh {assignment.educator} + +
+ +

{assignment.title}

+ +
+

+ {assignment.description} +

+
+ +
+
+

Tenggat Waktu

+

+ {new Date(assignment.dueDate).toLocaleString()} +

+
+
+

Nilai Maksimal

+

{assignment.maxScore}

+
+
+
+
+ + {/* Submission Sidebar */} +
+
+

Pengumpulan Tugas

+ +
+

Status:

+ + {assignment.status} + +
+ +
+
+ + + +

Upload File

+

Word (DOCX) atau PDF

+
+ + + Serahkan Tugas + +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/app/[locale]/(app)/dashboard/assignments/new/page.tsx b/app/[locale]/(app)/dashboard/assignments/new/page.tsx new file mode 100644 index 0000000..ad43ef4 --- /dev/null +++ b/app/[locale]/(app)/dashboard/assignments/new/page.tsx @@ -0,0 +1,141 @@ +/** + * File: page.tsx + * Created by: AI Assistant + * Date: 2025-11-29 + * Purpose: Create assignment page for kreatiVortex platform + * Part of: kreatiVortex - Platform Pembelajaran Tari Online + */ + +'use client'; + +import React, { useState, useEffect } from 'react'; +import { useRouter, useSearchParams } from 'next/navigation'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; + +export default function NewAssignmentPage() { + const router = useRouter(); + const searchParams = useSearchParams(); + const classId = searchParams.get('classId'); + const [loading, setLoading] = useState(false); + const [formData, setFormData] = useState({ + title: '', + description: '', + classId: '', + dueDate: '', + maxScore: 100, + }); + + useEffect(() => { + if (classId) { + setFormData(prev => ({ ...prev, classId })); + } + }, [classId]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + + // Simulate API call + setTimeout(() => { + setLoading(false); + router.push('/dashboard/assignments'); + }, 1000); + }; + + return ( +
+
+

Buat Tugas Baru

+

Berikan tugas kepada siswa untuk evaluasi pembelajaran

+
+ +
+
+ + setFormData({ ...formData, title: e.target.value })} + required + placeholder="Contoh: Analisis Gerakan Tari Piring" + className="bg-white/10 border-white/20 text-white placeholder:text-gray-400" + /> +
+ +
+ + +
+ +
+ + setFormData({ ...formData, dueDate: e.target.value })} + required + className="bg-white/10 border-white/20 text-white" + /> +
+ +
+ + +
+ + Kirim + +
+
+
+ + + + ); +} \ No newline at end of file diff --git a/app/[locale]/(app)/dashboard/videos/new/page.tsx b/app/[locale]/(app)/dashboard/videos/new/page.tsx new file mode 100644 index 0000000..10054e1 --- /dev/null +++ b/app/[locale]/(app)/dashboard/videos/new/page.tsx @@ -0,0 +1,44 @@ +import VideoForm from '@/components/Forms/VideoForm'; +import { prisma } from '@/lib/prisma'; +import { getLocale } from 'next-intl/server'; +import { createVideo } from '@/app/actions/video'; + +export default async function NewVideoPage() { + const locale = await getLocale(); + + const menus = await prisma.menu.findMany({ + where: { isActive: true }, + include: { + parent: true, + }, + orderBy: { createdAt: 'asc' }, + }); + + const getLocalizedName = (json: any) => { + if (!json) return ''; + return json[locale] || json['id'] || json['en'] || ''; + }; + + const formattedMenus = menus.map((menu) => { + const name = getLocalizedName(menu.name); + const parentName = menu.parent ? getLocalizedName(menu.parent.name) : ''; + return { + id: menu.id, + title: parentName ? `${parentName} > ${name}` : name, + }; + }); + + // Sort by title for better UX + formattedMenus.sort((a, b) => a.title.localeCompare(b.title)); + + return ( +
+
+

Upload Video Baru

+

Tambahkan video pembelajaran baru ke koleksi Anda

+
+ + +
+ ); +} \ No newline at end of file diff --git a/app/[locale]/(app)/dashboard/videos/page.tsx b/app/[locale]/(app)/dashboard/videos/page.tsx new file mode 100644 index 0000000..6597973 --- /dev/null +++ b/app/[locale]/(app)/dashboard/videos/page.tsx @@ -0,0 +1,335 @@ +/** + * File: page.tsx + * Created by: AI Assistant + * Date: 2025-11-29 + * Purpose: Video list page for kreatiVortex platform + * Part of: kreatiVortex - Platform Pembelajaran Tari Online + */ + +'use client'; + +import { Link } from '@/i18n/routing'; +import ActionButton from '@/components/ActionButton'; +import { useFetch } from '@/hooks/useFetch'; +import { useTranslations } from 'next-intl'; +import { useState, useEffect } from 'react'; +import { generateYoutubeEmbedUrl } from '@/lib/youtube'; +import { PlayIcon } from 'lucide-react'; +import { canUploadVideos } from '@/lib/admin'; + +interface VideoData extends Record { + id: string; + title: string; + description: string; + videoType: 'YOUTUBE' | 'LOCAL'; + viewCount: number; + createdAt: string; + isPublic: boolean; + uploaderId: string; + uploader: { + user: { + name: string; + }; + }; +} + +export default function VideosPage() { + const t = useTranslations('Videos'); + const { data: videos, loading } = useFetch('/api/videos'); + const [userProfile, setUserProfile] = useState(null); + + useEffect(() => { + // Fetch user profile to check permissions + const fetchProfile = async () => { + try { + const response = await fetch('/api/user/profile', { + credentials: 'include' + }); + if (response.ok) { + const data = await response.json(); + setUserProfile(data.data); + } + } catch (error) { + console.error('Error fetching user profile:', error); + } + }; + + fetchProfile(); + }, []); + + const handleDelete = async (videoId: string) => { + if (!confirm('Apakah Anda yakin ingin menghapus video ini?')) { + return; + } + + try { + const response = await fetch(`/api/videos/${videoId}`, { + method: 'DELETE', + credentials: 'include' + }); + + if (response.ok) { + // Refresh the videos list + window.location.reload(); + } else { + alert('Gagal menghapus video'); + } + } catch (error) { + console.error('Error deleting video:', error); + alert('Gagal menghapus video'); + } + }; + + const renderVideoActions = (video: any, userProfile: any, handleDelete: Function, t: Function) => { + const canEdit = userProfile && ( + userProfile.role?.name === 'ADMIN' || + userProfile.role?.name === 'PENDIDIK' || + video.uploaderId === userProfile.id + ); + + const canDelete = userProfile && ( + userProfile.role?.name === 'ADMIN' || + video.uploaderId === userProfile.id + ); + + return ( +
+ + + + + {t('actionView')} + + + {canEdit && ( + + + + + {t('actionEdit')} + + )} + + {canDelete && ( + + )} +
+ ); + }; + + return ( +
+
+
+

{t('title')}

+

{t('subtitle')}

+
+ {canUploadVideos(userProfile) && ( + + + {t('uploadButton')} + + + )} +
+ + {loading ? ( +
+
+

{t('loading')}

+
+ ) : videos && videos.length > 0 ? ( +
+ {videos.map((video) => ( +
+ {/* Video Thumbnail */} +
+ {video.videoType === 'YOUTUBE' ? ( +