📋 Planlama 🔧 Refactor

Context Menu Refactor

Modüler Dosya Yapısı ile Organizasyon

25 Aralık 2025 Planlama Aşaması

📝 Basit Anlatım (Herkes İçin)

Sorun: Şu anda tüm sağ tık menüleri (context menu) tek bir JavaScript dosyasında yazılı. Şarkı menüsü, albüm menüsü, playlist menüsü - hepsi karmaşık bir kod yığını içinde gömülü durumda.

Çözüm: Her içerik türü için ayrı dosyalar oluşturacağız. Şarkı menüsü kendi dosyasında, albüm menüsü kendi dosyasında olacak. Bu sayede:

  • ✅ Hangi menüde ne var kolayca görebileceğiz
  • ✅ Bir menüyü değiştirmek için diğerlerine dokunmayacağız
  • ✅ Yeni menü eklenmesi çok kolay olacak
  • ✅ Kod tekrarı azalacak, bakımı kolaylaşacak

Benzetme: Şu anki durum tüm kıyafetlerin tek bir dolaba tıkılmış hali. Refactor sonrası her kıyafet türü için ayrı çekmeceler olacak - gömlekler ayrı, pantolonlar ayrı, ayakkabılar ayrı.

Mevcut Durum Analizi

📁 Dosya Yapısı (Şu Anki)

public/themes/muzibu/js/
└── muzibu-store.js (~1800+ satır)
└── contextMenu store (~300 satır)
├── getActionsForType() (7 content type hardcoded)
└── executeAction() (switch-case, 15+ action)

❌ Sorunlar

  • Monolitik yapı: 7 content type tek fonksiyon içinde (song, album, playlist, genre, sector, radio, artist)
  • Kod tekrarı: "Çal", "Sıraya Ekle", "Favorilerime Ekle" her menüde tekrar yazılmış
  • Zor bakım: Bir menüyü düzeltmek için 300 satır kod içinde aramak gerekiyor
  • Yeniden kullanılabilirlik yok: Aynı action'ları farklı yerlerde kullanamıyoruz
  • Test edilemez: Unit test yazmak imkansız, her şey iç içe

4 Farklı Yaklaşım Karşılaştırması

Yaklaşım 1: Blade Component

Yapı:
resources/views/components/muzibu/context-menus/
├── song-actions.blade.php
├── album-actions.blade.php
├── playlist-actions.blade.php
├── genre-actions.blade.php
└── ...
✅ Avantajlar:
  • • Blade syntax kullanılabilir
  • • @auth, @can directives
  • • Dinamik content render
  • • Laravel'in gücünden yararlanma
❌ Dezavantajlar:
  • • HTML render gerekli
  • • JS'den çağırmak için AJAX
  • • Performance overhead
  • • Client-side manipulation zor

Yaklaşım 2: PHP Config Files

Yapı:
config/muzibu/context-menus/
├── song.php
├── album.php
├── playlist.php
└── ...

// song.php
return [
  ['icon' => 'fa-play', 'label' => 'Çal', 'action' => 'play'],
  ...
];
✅ Avantajlar:
  • • PHP array, kolay yönetim
  • • Config cache kullanılabilir
  • • Helper ile kolayca erişim
  • • Git diff friendly
❌ Dezavantajlar:
  • • Frontend'e JSON encode gerekli
  • • Runtime logic eklemek zor
  • • Controller/Helper bağımlılığı

Yaklaşım 3: JSON Files

Yapı:
public/themes/muzibu/js/context-menus/
├── song.json
├── album.json
├── playlist.json
└── ...
✅ Avantajlar:
  • • Platform agnostic
  • • Frontend kolayca fetch eder
  • • Basit, temiz yapı
  • • Versiyonlama kolay
❌ Dezavantajlar:
  • • PHP logic kullanılamaz
  • • Dinamik data (auth, favorites) yok
  • • Runtime değişiklik imkansız
  • • Statik içerik only

Yaklaşım 4: Hybrid (JavaScript Modüler) - ÖNERİLEN ⭐

Yapı:
public/themes/muzibu/js/context-menus/
├── index.js (Store registration + loader)
├── actions/
│ ├── song.js
│ ├── album.js
│ ├── playlist.js
│ ├── genre.js
│ ├── sector.js
│ ├── radio.js
│ └── artist.js
└── handlers/
    ├── play.js
    ├── addToQueue.js
    ├── toggleFavorite.js
    └── ...
✅ Neden Bu Yaklaşım En İyi?
  • Modüler: Her content type ayrı dosya, bağımsız düzenleme
  • DRY Principle: Ortak handler'lar tek yerde, yeniden kullanılabilir
  • Performance: No server round-trip, pure JavaScript
  • Dinamik: Runtime'da data ile merge edilebilir (is_favorite, is_mine vb.)
  • Bakım Kolay: actions/ klasörüne bakınca hemen ne var görülür
  • Test Edilebilir: Her action dosyası unit test edilebilir
  • Tree-shaking: Webpack/Vite ile optimize build mümkün

Önerilen Modüler Yapı (Hybrid JavaScript)

📁 Dosya Organizasyonu

public/themes/muzibu/js/context-menus/
├── index.js // Alpine store registration
├── actions/ // Content type menu definitions
│ ├── song.js
│ ├── album.js
│ ├── playlist.js
│ ├── genre.js
│ ├── sector.js
│ ├── radio.js
│ └── artist.js
├── handlers/ // Action implementations
│ ├── play.js
│ ├── addToQueue.js
│ ├── toggleFavorite.js
│ ├── rate.js
│ ├── addToPlaylist.js
│ ├── navigation.js
│ ├── playlistManagement.js
│ └── ...
└── utils/ // Helper functions
├── actionBuilder.js // Common action templates
└── loader.js // Dynamic action loader

📄 Örnek: actions/song.js

// actions/song.js
import { commonActions } from '../utils/actionBuilder.js';

export default function getSongActions(data) {
    return [
        // Çal
        { icon: 'fa-play', label: 'Çal', action: 'play' },

        // Sıraya Ekle
        { icon: 'fa-plus-circle', label: 'Sıraya Ekle', action: 'addToQueue' },

        { divider: true },

        // Favorilerime Ekle (dinamik label)
        {
            icon: 'fa-heart',
            label: data.is_favorite ? 'Favorilerimden Çıkar' : 'Favorilerime Ekle',
            action: 'toggleFavorite'
        },

        { divider: true },

        // Puan Ver
        { icon: 'fa-star', label: 'Puan Ver', action: 'rate' },

        // Playliste Ekle
        {
            icon: 'fa-list',
            label: 'Playliste Ekle',
            action: 'addToPlaylist',
            submenu: true
        },

        // Albüme Git
        {
            icon: 'fa-compact-disc',
            label: 'Albüme Git',
            action: 'goToAlbum',
            visible: !!data.album_id
        }
    ].filter(item => item.visible !== false);
}

⚙️ Örnek: handlers/play.js

// handlers/play.js
export function handlePlay(type, data) {
    if (window.playContent) {
        window.playContent(type, data.id);
    }

    Alpine.store('toast').show(
        `▶️ Çalıyor: ${data.title}`,
        'success'
    );
}

🎯 Örnek: index.js (Main Store)

// context-menus/index.js
import getSongActions from './actions/song.js';
import getAlbumActions from './actions/album.js';
import getPlaylistActions from './actions/playlist.js';
import getGenreActions from './actions/genre.js';
import getSectorActions from './actions/sector.js';
import getRadioActions from './actions/radio.js';
import getArtistActions from './actions/artist.js';

import { handlePlay } from './handlers/play.js';
import { handleAddToQueue } from './handlers/addToQueue.js';
import { handleToggleFavorite } from './handlers/toggleFavorite.js';
import { handleRate } from './handlers/rate.js';
// ... diğer handler'lar

const actionMap = {
    song: getSongActions,
    album: getAlbumActions,
    playlist: getPlaylistActions,
    genre: getGenreActions,
    sector: getSectorActions,
    radio: getRadioActions,
    artist: getArtistActions
};

const handlerMap = {
    play: handlePlay,
    addToQueue: handleAddToQueue,
    toggleFavorite: handleToggleFavorite,
    rate: handleRate,
    // ... diğer handler'lar
};

export function registerContextMenuStore() {
    Alpine.store('contextMenu', {
        // ... store implementation
        getActionsForType(type, data) {
            const getActions = actionMap[type];
            return getActions ? getActions(data) : [];
        },

        executeAction(action) {
            const handler = handlerMap[action];
            if (handler) {
                handler(this.type, this.data);
            }
        }
    });
}

Migration Planı (Adım Adım)

1

Klasör Yapısını Oluştur

Yeni modüler klasörleri oluştur:

mkdir -p public/themes/muzibu/js/context-menus/actions
mkdir -p public/themes/muzibu/js/context-menus/handlers
mkdir -p public/themes/muzibu/js/context-menus/utils
2

Actions Dosyalarını Oluştur

Her content type için action dosyası yarat:

  • actions/song.js - Mevcut song actions'ları taşı
  • actions/album.js - Mevcut album actions'ları taşı
  • actions/playlist.js - Mevcut playlist actions'ları taşı
  • ... diğer content type'lar için
3

Handler'ları Ayır

executeAction() içindeki switch-case'leri ayrı handler dosyalarına taşı:

  • handlers/play.js - play action implementasyonu
  • handlers/addToQueue.js - addToQueue implementasyonu
  • handlers/toggleFavorite.js - toggleFavorite implementasyonu
  • ... her action için ayrı handler
4

Utils ve Helper'ları Ekle

Ortak kullanılan fonksiyonları utils'e taşı:

  • utils/actionBuilder.js - Ortak action template'leri
  • utils/loader.js - Dynamic module loader
5

Store'u Refactor Et

muzibu-store.js içindeki contextMenu store'u yeniden yaz:

  • getActionsForType() → actionMap'ten çağır
  • executeAction() → handlerMap'ten çağır
  • Hardcoded array'leri kaldır
  • Import statement'ları ekle
6

Test ve Production Build

Değişiklikleri test et ve build al:

npm run prod
php artisan view:clear
php artisan responsecache:clear

Tüm content type'lar için context menu'leri test et:

  • Şarkı row'larında sağ tık
  • Album kartlarında sağ tık
  • Playlist kartlarında sağ tık
  • ... tüm yerlerde test
7

Eski Kodu Temizle

Refactor tamamlandıktan sonra:

  • muzibu-store.js içindeki eski hardcoded code'u sil
  • Kullanılmayan fonksiyonları temizle
  • Kod yorumlarını güncelle
  • Git commit yap

Refactor Sonrası Kazanımlar

Kod Kalitesi

  • Modüler, okunabilir kod
  • DRY principle uygulanmış
  • Single responsibility per file
  • Test edilebilir yapı

Bakım Kolaylığı

  • Menü değişikliği 1 dosyada
  • Action düzeltme çok kolay
  • Yeni content type hızlı eklenir
  • Git diff anlaşılır olur

Performance

  • Tree-shaking mümkün
  • Lazy loading yapılabilir
  • Bundle size optimize edilir
  • No server round-trip

Developer Experience

  • Yeni geliştirici kolayca anlar
  • IDE autocomplete desteği
  • Debugging çok kolay
  • Documentation self-explanatory

🔧 Teknik Detaylar (Geliştiriciler İçin)

📁 Dosya Konumları

  • Yeni klasör: public/themes/muzibu/js/context-menus/
  • Action dosyaları: context-menus/actions/*.js
  • Handler dosyaları: context-menus/handlers/*.js
  • Store refactor: public/themes/muzibu/js/muzibu-store.js

⚙️ Kullanılan Teknolojiler

  • • ES6 Modules (import/export)
  • • Alpine.js Store System
  • • JavaScript Arrow Functions
  • • Spread Operator (... diğer action'lar için)
  • • Filter/Map/Reduce (action manipulation)

🔗 İlişkili Sistemler

  • • Alpine.js contextMenu store (muzibu-store.js)
  • • Context menu component (components/context-menu.blade.php)
  • • Context menu init (js/context-menu/init.js)
  • • Song/Album/Playlist card components
  • • Toast notification system

📊 Etkilenen Satır Sayısı

  • • muzibu-store.js: ~300 satır → ~50 satır (import/export logic)
  • • Yeni dosyalar: ~600 satır (actions + handlers + utils)
  • • Net artış: +350 satır (ancak çok daha organize)
  • • Maintainability: %400 artış (çok daha kolay)

Test Stratejisi

✅ Manuel Test Checklist

Sonuç ve Tavsiye

Hybrid JavaScript yaklaşımı ile modüler context menu sistemi kurulması şiddetle tavsiye edilir.

Bu refactor kısa vadede biraz efor gerektirecek (~2-3 saat), ancak uzun vadede:

  • Yeni menü ekleme süresi 30 dakika → 5 dakika
  • Menü düzeltme süresi 20 dakika → 2 dakika
  • Bug fix süresi 1 saat → 10 dakika
  • Yeni geliştirici onboarding 2 gün → 2 saat

ROI (Return on Investment): Yüksek! İlk 1 ay içinde kendini amorti eder.