Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_koding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: 🐞 Bug (Divisi Koding / Bounty)
about: Temuan bug dari event atau kontribusi divisi Koding
title: '[BUG] '
labels: bug, koding
assignees: ''
---

## Ringkasan
Satu kalimat: apa yang salah.

## Langkah Reproduksi
1.
2.
3.

## Hasil Aktual vs Diharapkan
- Aktual:
- Diharapkan:

## Bukti
Screenshot / rekaman / console log.

## Lokasi (opsional)
File / halaman / komponen yang dicurigai.

## Severity usulan pelapor
- [ ] Critical (keamanan, data bocor, site down)
- [ ] High (fitur utama rusak)
- [ ] Medium (fitur rusak sebagian)
- [ ] Low (visual / typo)

> Bug keamanan **jangan** dilaporkan di sini. Lihat SECURITY.md.
10 changes: 8 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Jelaskan perubahan yang kamu buat secara singkat.

## 🔗 Issue Terkait

Fixes #(nomor issue)
Closes #(nomor issue)

## 🔄 Tipe Perubahan

Expand All @@ -28,7 +28,13 @@ Fixes #(nomor issue)
- [ ] Saya sudah menambahkan komentar di bagian yang kompleks
- [ ] Saya sudah update dokumentasi yang terkait
- [ ] Perubahan saya tidak menghasilkan warning baru
- [ ] Saya sudah test perubahan saya secara lokal
- [ ] Saya sudah test perubahan saya secara lokal (desktop dan mobile bila menyentuh UI)
- [ ] `npx tsc --noEmit` dan `npm run build` lolos
- [ ] Tidak ada secret atau data pribadi di diff

## 🧪 Cara Verifikasi

Langkah agar reviewer bisa memastikan perubahan bekerja.

## 📝 Catatan untuk Reviewer

Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: CI

on:
pull_request:
push:
branches: [main]

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- name: Typecheck
run: npx tsc --noEmit
- name: Build
run: npm run build
env:
VITE_SUPABASE_URL: https://example.supabase.co
VITE_SUPABASE_ANON_KEY: ci-placeholder
51 changes: 51 additions & 0 deletions .github/workflows/event-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Event report

on:
workflow_dispatch:
inputs:
since:
description: 'Tanggal mulai (YYYY-MM-DD)'
required: true
until:
description: 'Tanggal akhir (YYYY-MM-DD, kosong = hari ini)'
required: false
schedule:
- cron: '0 1 * * 1' # tiap Senin 08:00 WIB

permissions:
contents: read
issues: read
pull-requests: read

jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Hitung periode
id: range
run: |
SINCE="${{ github.event.inputs.since }}"
if [ -z "$SINCE" ]; then SINCE="$(date -u -d '7 days ago' +%F)"; fi
echo "since=$SINCE" >> "$GITHUB_OUTPUT"
echo "until=${{ github.event.inputs.until }}" >> "$GITHUB_OUTPUT"
- name: Buat laporan
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPO: ${{ github.repository }}
SINCE: ${{ steps.range.outputs.since }}
UNTIL: ${{ steps.range.outputs.until }}
run: |
if [ -n "$UNTIL" ]; then
node scripts/event-report.mjs --since "$SINCE" --until "$UNTIL" --out report
else
node scripts/event-report.mjs --since "$SINCE" --out report
fi
cat report.md >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@v4
with:
name: event-report
path: report.*
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dist-ssr
.env
.env.production
.env.staging
.env.local

# Editor directories and files
.vscode/*
Expand All @@ -28,3 +29,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
event/report.*
private/
Binary file removed build_log.txt
Binary file not shown.
145 changes: 0 additions & 145 deletions build_log_utf8.txt

This file was deleted.

17 changes: 11 additions & 6 deletions components/AuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
import { User, Session } from '@supabase/supabase-js';
import { supabase } from '../lib/supabase';

Expand Down Expand Up @@ -28,6 +28,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const [user, setUser] = useState<User | null>(null);
const [profile, setProfile] = useState<Profile | null>(null);
const [loading, setLoading] = useState(true);
const currentUserId = useRef<string | null>(null);

useEffect(() => {
if (import.meta.env.DEV) console.log('AuthProvider: Starting initialization...');
Expand All @@ -42,6 +43,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const getInitialSession = async () => {
try {
const { data: { session } } = await supabase.auth.getSession();
currentUserId.current = session?.user?.id ?? null;
setSession(session);
setUser(session?.user ?? null);

Expand All @@ -61,14 +63,17 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
getInitialSession();

// 2. Pantau perubahan auth (login/logout)
const { data: { subscription } } = supabase.auth.onAuthStateChange(async (_event, session) => {
const previousUser = user;
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
const previousId = currentUserId.current;
currentUserId.current = session?.user?.id ?? null;
setSession(session);
setUser(session?.user ?? null);

// Cek apakah user berubah beneran biar gak fetch ulang kalo cuma token refresh
if (session?.user && session.user.id !== previousUser?.id) {
await fetchProfile(session.user.id);
// Cek apakah user berubah beneran biar gak fetch ulang kalo cuma token refresh.
// Jangan await panggilan Supabase di dalam callback ini (bisa deadlock), jadi ditunda.
if (session?.user && session.user.id !== previousId) {
const userId = session.user.id;
setTimeout(() => { void fetchProfile(userId); }, 0);
} else if (!session?.user) {
setProfile(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export const InteractiveSandbox: React.FC<InteractiveSandboxProps> = ({ files, t
ref={iframeRef}
srcDoc={getIframeContent()}
className="w-full h-full border-none bg-black"
sandbox="allow-scripts allow-modals allow-same-origin"
sandbox="allow-scripts allow-modals"
title="Preview"
/>
);
Expand Down
7 changes: 5 additions & 2 deletions components/CreationStudio/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,11 @@ export const CreationStudio: React.FC<Props> = ({ isOpen, onClose, onPublish })
};

const uploadFile = async (file: File): Promise<string> => {
const fileExt = file.name.split('.').pop();
const fileName = `${Math.random()}.${fileExt}`;
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'video/mp4', 'video/webm'];
if (!allowedTypes.includes(file.type)) throw new Error('Tipe file tidak diizinkan.');
if (file.size > 50 * 1024 * 1024) throw new Error('Ukuran file maksimal 50MB.');
const fileExt = file.name.split('.').pop()?.toLowerCase().replace(/[^a-z0-9]/g, '') || 'bin';
const fileName = `${crypto.randomUUID()}.${fileExt}`;
const filePath = `${fileName}`;

const { error: uploadError } = await supabase.storage
Expand Down
5 changes: 4 additions & 1 deletion components/MediaUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,13 @@ const MediaUploader = ({
disabled: uploading,
});

// framer-motion punya tipe onDrag sendiri yang bentrok dengan react-dropzone
const { onDrag: _onDrag, onDragStart: _onDragStart, onDragEnd: _onDragEnd, onAnimationStart: _onAnimationStart, ...rootProps } = getRootProps();

return (
<div className="w-full">
<motion.div
{...getRootProps()}
{...rootProps}
whileHover={{ scale: uploading ? 1 : 1.02 }}
className={`
relative border-2 border-dashed rounded-xl p-8 text-center cursor-pointer transition-all
Expand Down
Loading
Loading