feat: Complete licensing module with admin and customer UIs

Admin SPA:
- Licenses list page with search, filter, pagination
- License detail page with activation history
- Copy license key, view details, revoke functionality

Customer SPA:
- My Account > Licenses page
- View licenses with activation info
- Copy license key
- Deactivate devices

Backend integration:
- Routes registered in App.tsx and Account/index.tsx
- License nav item in account sidebar (conditional on module enabled)
This commit is contained in:
Dwindi Ramadhana
2026-01-05 16:29:37 +07:00
parent b367c1fcf8
commit 3d2bab90ec
6 changed files with 798 additions and 5 deletions

View File

@@ -1,6 +1,6 @@
import React, { ReactNode, useState, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { LayoutDashboard, ShoppingBag, Download, MapPin, Heart, User, LogOut } from 'lucide-react';
import { LayoutDashboard, ShoppingBag, Download, MapPin, Heart, User, LogOut, Key } from 'lucide-react';
import { useModules } from '@/hooks/useModules';
import { api } from '@/lib/api/client';
import {
@@ -53,13 +53,16 @@ export function AccountLayout({ children }: AccountLayoutProps) {
{ id: 'downloads', label: 'Downloads', path: '/my-account/downloads', icon: Download },
{ id: 'addresses', label: 'Addresses', path: '/my-account/addresses', icon: MapPin },
{ id: 'wishlist', label: 'Wishlist', path: '/my-account/wishlist', icon: Heart },
{ id: 'licenses', label: 'Licenses', path: '/my-account/licenses', icon: Key },
{ id: 'account-details', label: 'Account Details', path: '/my-account/account-details', icon: User },
];
// Filter out wishlist if module disabled or settings disabled
const menuItems = allMenuItems.filter(item =>
item.id !== 'wishlist' || (isEnabled('wishlist') && wishlistEnabled)
);
// Filter out wishlist if module disabled or settings disabled, licenses if licensing disabled
const menuItems = allMenuItems.filter(item => {
if (item.id === 'wishlist') return isEnabled('wishlist') && wishlistEnabled;
if (item.id === 'licenses') return isEnabled('licensing');
return true;
});
const handleLogout = async () => {
setIsLoggingOut(true);