lucide-react komponenti kaldırıldı.

This commit is contained in:
Sedat Öztürk 2025-08-16 22:47:24 +03:00
parent 4fada60029
commit 8ddede546d
61 changed files with 877 additions and 11810 deletions

View file

@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "index.html", "url": "index.html",
"revision": "0.7jvpk79jec" "revision": "0.mmr753hmff"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

11051
ui/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -45,7 +45,6 @@
"jspdf": "^3.0.1", "jspdf": "^3.0.1",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.484.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-advanced-cropper": "^0.20.0", "react-advanced-cropper": "^0.20.0",
"react-arborist": "^3.4.0", "react-arborist": "^3.4.0",

View file

@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'
import Editor from '@monaco-editor/react' import Editor from '@monaco-editor/react'
import { ComponentDefinition } from '../../@types/componentInfo' import { ComponentDefinition } from '../../@types/componentInfo'
import { generateSingleComponentJSX, generateUniqueId } from '@/utils/codeParser' import { generateSingleComponentJSX, generateUniqueId } from '@/utils/codeParser'
import { Check, Code, Loader, MousePointer, Save, Settings, X } from 'lucide-react' import { FaCheck, FaCode, FaSpinner, FaMousePointer, FaSave, FaCog, FaTimes } from 'react-icons/fa'
interface CodeEditorProps { interface CodeEditorProps {
code: string code: string
@ -427,9 +427,9 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
className="px-3 py-2 bg-gray-700 text-gray-300 rounded-lg text-xs font-medium hover:bg-gray-600 transition-colors flex items-center gap-2 disabled:opacity-50" className="px-3 py-2 bg-gray-700 text-gray-300 rounded-lg text-xs font-medium hover:bg-gray-600 transition-colors flex items-center gap-2 disabled:opacity-50"
> >
{isFormatting ? ( {isFormatting ? (
<Loader className="w-4 h-4 animate-spin" /> <FaSpinner className="w-4 h-4 animate-spin" />
) : ( ) : (
<Code className="w-4 h-4" /> <FaCode className="w-4 h-4" />
)} )}
Formatla Formatla
</button> </button>
@ -442,7 +442,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
: 'bg-gray-700 text-gray-300 hover:bg-gray-600' : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
}`} }`}
> >
<Settings className="w-4 h-4" /> <FaCog className="w-4 h-4" />
Ayarlar Ayarlar
</button> </button>
@ -450,7 +450,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
onClick={handleResetChanges} onClick={handleResetChanges}
className="px-3 py-2 bg-red-600 text-white rounded-lg text-xs font-medium hover:bg-red-700 transition-colors flex items-center gap-2" className="px-3 py-2 bg-red-600 text-white rounded-lg text-xs font-medium hover:bg-red-700 transition-colors flex items-center gap-2"
> >
<X className="w-4 h-4" /> <FaTimes className="w-4 h-4" />
Sıfırla Sıfırla
</button> </button>
@ -458,7 +458,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
onClick={handleApplyChanges} onClick={handleApplyChanges}
className="px-3 py-2 bg-green-600 text-white rounded-lg text-xs font-medium hover:bg-green-700 transition-colors flex items-center gap-2" className="px-3 py-2 bg-green-600 text-white rounded-lg text-xs font-medium hover:bg-green-700 transition-colors flex items-center gap-2"
> >
<Check className="w-4 h-4" /> <FaCheck className="w-4 h-4" />
Uygula Uygula
</button> </button>
</div> </div>
@ -467,7 +467,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
onClick={onComponentSave} onClick={onComponentSave}
className="flex items-center gap-2 bg-yellow-600 text-white px-4 py-2 rounded-lg hover:bg-yellow-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm" className="flex items-center gap-2 bg-yellow-600 text-white px-4 py-2 rounded-lg hover:bg-yellow-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm"
> >
<Save className="w-4 h-4" /> <FaSave className="w-4 h-4" />
Kaydet Kaydet
</button> </button>
</div> </div>
@ -622,12 +622,12 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
{hasChanges && <span className="text-orange-400"> Kaydedilmemiş değişiklikler</span>} {hasChanges && <span className="text-orange-400"> Kaydedilmemiş değişiklikler</span>}
{showSuccessMessage && ( {showSuccessMessage && (
<span className="text-green-400 flex items-center gap-1"> <span className="text-green-400 flex items-center gap-1">
<Check className="w-4 h-4" /> <FaCheck className="w-4 h-4" />
</span> </span>
)} )}
{isDragOver && ( {isDragOver && (
<span className="text-blue-400 flex items-center gap-1"> <span className="text-blue-400 flex items-center gap-1">
<MousePointer className="w-4 h-4" /> <FaMousePointer className="w-4 h-4" />
Bileşeni bırakmaya hazır Bileşeni bırakmaya hazır
</span> </span>
)} )}

View file

@ -1,8 +1,9 @@
import React, { useMemo, useState } from "react"; import React, { useMemo, useState } from "react";
import { Search, Square } from "lucide-react"; import { FaSquare } from 'react-icons/fa';
import * as Icons from "lucide-react"; import { AiOutlineSearch } from 'react-icons/ai';
import { ComponentDefinition, HookInfo, PropertyInfo } from "../../@types/componentInfo"; import { ComponentDefinition, HookInfo, PropertyInfo } from "../../@types/componentInfo";
import { getAllComponentDefinitions } from "./data/componentDefinitions"; import { getAllComponentDefinitions } from "./data/componentDefinitions";
import navigationIcon from "@/configs/navigation-icon.config";
interface ComponentLibraryProps { interface ComponentLibraryProps {
onDragStart: (componentDef: ComponentDefinition, e: React.DragEvent) => void; onDragStart: (componentDef: ComponentDefinition, e: React.DragEvent) => void;
@ -86,9 +87,8 @@ export const ComponentLibrary: React.FC<ComponentLibraryProps> = ({
})) }))
.filter((cat) => cat.components.length > 0); .filter((cat) => cat.components.length > 0);
const getIcon = (iconName: string) => { const getIcon = (iconName: string): React.ComponentType<any> => {
const IconComponent = (Icons as any)[iconName]; return navigationIcon[iconName] || FaSquare;
return IconComponent || Square;
}; };
return ( return (
@ -96,7 +96,7 @@ export const ComponentLibrary: React.FC<ComponentLibraryProps> = ({
{/* Arama kutusu */} {/* Arama kutusu */}
<div className="p-4 border-b border-gray-700"> <div className="p-4 border-b border-gray-700">
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" /> <AiOutlineSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<input <input
type="text" type="text"
placeholder="Search Components..." placeholder="Search Components..."

View file

@ -1,5 +1,11 @@
import React from "react"; import React from "react";
import { Settings, X, PanelTop as Panels, Eye, EyeOff } from "lucide-react"; import {
FaCog,
FaTimes,
FaBars,
FaEye,
FaEyeSlash
} from 'react-icons/fa';
import { PanelState } from "./data/componentDefinitions"; import { PanelState } from "./data/componentDefinitions";
interface PanelManagerProps { interface PanelManagerProps {
@ -19,8 +25,8 @@ export const PanelManager: React.FC<PanelManagerProps> = ({
if (!isOpen) return null; if (!isOpen) return null;
const paneller = [ const paneller = [
{ key: "toolbox" as keyof PanelState, label: "Toolbox", icon: Panels }, { key: "toolbox" as keyof PanelState, label: "Toolbox", icon: FaBars },
{ key: "properties" as keyof PanelState, label: "Properties", icon: Settings }, { key: "properties" as keyof PanelState, label: "Properties", icon: FaCog },
]; ];
return ( return (
@ -28,7 +34,7 @@ export const PanelManager: React.FC<PanelManagerProps> = ({
<div className="bg-white rounded-lg shadow-xl w-96 max-w-full mx-4"> <div className="bg-white rounded-lg shadow-xl w-96 max-w-full mx-4">
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Panels className="w-5 h-5 text-blue-600" /> <FaBars className="w-5 h-5 text-blue-600" />
<h2 className="text-lg font-semibold text-gray-900">Panel Manager</h2> <h2 className="text-lg font-semibold text-gray-900">Panel Manager</h2>
</div> </div>
<button <button
@ -36,7 +42,7 @@ export const PanelManager: React.FC<PanelManagerProps> = ({
className="p-1 hover:bg-gray-100 rounded transition-colors" className="p-1 hover:bg-gray-100 rounded transition-colors"
title="Kapat" title="Kapat"
> >
<X className="w-5 h-5 text-gray-500" /> <FaTimes className="w-5 h-5 text-gray-500" />
</button> </button>
</div> </div>
<div className="p-4"> <div className="p-4">
@ -54,7 +60,7 @@ export const PanelManager: React.FC<PanelManagerProps> = ({
className={`p-1 rounded transition-colors ${panelState[key] ? "text-blue-600 hover:bg-blue-100" : "text-gray-400 hover:bg-gray-200"}`} className={`p-1 rounded transition-colors ${panelState[key] ? "text-blue-600 hover:bg-blue-100" : "text-gray-400 hover:bg-gray-200"}`}
title={panelState[key] ? "Hide" : "Show"} title={panelState[key] ? "Hide" : "Show"}
> >
{panelState[key] ? <Eye className="w-4 h-4" /> : <EyeOff className="w-4 h-4" />} {panelState[key] ? <FaEye className="w-4 h-4" /> : <FaEyeSlash className="w-4 h-4" />}
</button> </button>
</div> </div>
))} ))}

View file

@ -1,105 +1,103 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react'
import * as Babel from "@babel/standalone"; import * as Babel from '@babel/standalone'
import axios from "axios"; import axios from 'axios'
import { import { useComponents } from '../../contexts/ComponentContext'
Alert, import ErrorBoundary from './ErrorBoundary'
Avatar, import { toast } from '../ui'
Badge,
Button,
Calendar,
Card,
Checkbox,
ConfigProvider,
DatePicker,
Dialog,
Drawer,
Dropdown,
FormItem,
FormContainer,
Input,
InputGroup,
Menu,
MenuItem,
Notification,
Pagination,
Progress,
Radio,
RangeCalendar,
ScrollBar,
Segment,
Select,
Skeleton,
Spinner,
Steps,
Switcher,
Table,
Tabs,
Tag,
TimeInput,
Timeline,
toast,
Tooltip,
Upload,
} from "../ui";
import { useComponents } from "../../contexts/ComponentContext";
import ErrorBoundary from "./ErrorBoundary";
const compileComponent = (code: string, scope: Record<string, any> = {}) => { const compileComponent = (code: string, scope: Record<string, any> = {}) => {
const transpiled = Babel.transform(code, { const transpiled = Babel.transform(code, {
filename: "component.tsx", filename: 'component.tsx',
presets: ["typescript", "react"], presets: ['typescript', 'react'],
plugins: ["transform-modules-commonjs"], plugins: ['transform-modules-commonjs'],
}).code; }).code
const module = { exports: {} }; const module = { exports: {} }
const require = (moduleName: string) => { const require = (moduleName: string) => {
if (moduleName === "react") return React; if (moduleName === 'react') return React
if (moduleName === "axios") return axios; if (moduleName === 'axios') return axios
throw new Error(`Modül bulunamadı: ${moduleName}`); throw new Error(`Modül bulunamadı: ${moduleName}`)
}; }
const scopedEval = new Function( const scopedEval = new Function(
"module", 'module',
"exports", 'exports',
"require", 'require',
...Object.keys(scope), ...Object.keys(scope),
transpiled! transpiled!,
); )
scopedEval(module, module.exports, require, ...Object.values(scope)); scopedEval(module, module.exports, require, ...Object.values(scope))
const compiledModule = module.exports as any; const compiledModule = module.exports as any
return compiledModule.default; return compiledModule.default
}; }
interface DynamicRendererProps { interface DynamicRendererProps {
componentName: string; componentName: string
dependencies?: string[]; dependencies?: string[]
} }
const DynamicRenderer: React.FC<DynamicRendererProps> = ({ const DynamicRenderer: React.FC<DynamicRendererProps> = ({
componentName, componentName,
dependencies: externalDeps, dependencies: externalDeps,
}) => { }) => {
const [Component, setComponent] = useState<React.ComponentType<any> | null>( // Lazy load for UI components
null const Alert = React.lazy(() => import('../ui/Alert'))
); const Avatar = React.lazy(() => import('../ui/Avatar'))
const { getComponentByName, components } = useComponents(); const Badge = React.lazy(() => import('../ui/Badge'))
const Button = React.lazy(() => import('../ui/Button'))
const Calendar = React.lazy(() => import('../ui/Calendar'))
const Card = React.lazy(() => import('../ui/Card'))
const Checkbox = React.lazy(() => import('../ui/Checkbox'))
const ConfigProvider = React.lazy(() => import('../ui/ConfigProvider'))
const DatePicker = React.lazy(() => import('../ui/DatePicker'))
const Dialog = React.lazy(() => import('../ui/Dialog'))
const Drawer = React.lazy(() => import('../ui/Drawer'))
const Dropdown = React.lazy(() => import('../ui/Dropdown'))
const FormItem = React.lazy(() => import('../ui/Form/FormItem'))
const FormContainer = React.lazy(() => import('../ui/Form/FormContainer'))
const Input = React.lazy(() => import('../ui/Input'))
const InputGroup = React.lazy(() => import('../ui/InputGroup'))
const Menu = React.lazy(() => import('../ui/Menu'))
const MenuItem = React.lazy(() => import('../ui/MenuItem'))
const Notification = React.lazy(() => import('../ui/Notification'))
const Pagination = React.lazy(() => import('../ui/Pagination'))
const Progress = React.lazy(() => import('../ui/Progress'))
const Radio = React.lazy(() => import('../ui/Radio'))
const RangeCalendar = React.lazy(() => import('../ui/RangeCalendar'))
const ScrollBar = React.lazy(() => import('../ui/ScrollBar'))
const Segment = React.lazy(() => import('../ui/Segment'))
const Select = React.lazy(() => import('../ui/Select'))
const Skeleton = React.lazy(() => import('../ui/Skeleton'))
const Spinner = React.lazy(() => import('../ui/Spinner'))
const Steps = React.lazy(() => import('../ui/Steps'))
const Switcher = React.lazy(() => import('../ui/Switcher'))
const Table = React.lazy(() => import('../ui/Table'))
const Tabs = React.lazy(() => import('../ui/Tabs'))
const Tag = React.lazy(() => import('../ui/Tag'))
const TimeInput = React.lazy(() => import('../ui/TimeInput'))
const Timeline = React.lazy(() => import('../ui/Timeline'))
const Tooltip = React.lazy(() => import('../ui/Tooltip'))
const Upload = React.lazy(() => import('../ui/Upload'))
const [Component, setComponent] = useState<React.ComponentType<any> | null>(null)
const { getComponentByName, components } = useComponents()
useEffect(() => { useEffect(() => {
setComponent(null); setComponent(null)
const storedComponent = getComponentByName(componentName); const storedComponent = getComponentByName(componentName)
if (!storedComponent) return; if (!storedComponent) return
const map = new Map( const map = new Map(
components.map((c) => { components.map((c) => {
// Parse dependencies from JSON string // Parse dependencies from JSON string
let componentDeps: string[] = []; let componentDeps: string[] = []
try { try {
componentDeps = c.dependencies ? JSON.parse(c.dependencies) : []; componentDeps = c.dependencies ? JSON.parse(c.dependencies) : []
} catch { } catch {
componentDeps = []; componentDeps = []
} }
return [ return [
@ -109,11 +107,11 @@ const DynamicRenderer: React.FC<DynamicRendererProps> = ({
jsx_code: c.code, jsx_code: c.code,
dependencies: Array.isArray(componentDeps) ? componentDeps : [], dependencies: Array.isArray(componentDeps) ? componentDeps : [],
}, },
]; ]
}) }),
); )
const compiled: Record<string, any> = {}; const compiled: Record<string, any> = {}
const staticComponents: Record<string, any> = { const staticComponents: Record<string, any> = {
Alert, Alert,
@ -154,53 +152,51 @@ const DynamicRenderer: React.FC<DynamicRendererProps> = ({
toast, toast,
Tooltip, Tooltip,
Upload, Upload,
}; }
const compileWithDependencies = (name: string): any => { const compileWithDependencies = (name: string): any => {
if (compiled[name]) return compiled[name]; if (compiled[name]) return compiled[name]
const entry = map.get(name); const entry = map.get(name)
if (!entry && staticComponents[name]) { if (!entry && staticComponents[name]) {
compiled[name] = staticComponents[name]; compiled[name] = staticComponents[name]
return staticComponents[name]; return staticComponents[name]
} }
if (!entry) throw new Error(`Component ${name} not found`); if (!entry) throw new Error(`Component ${name} not found`)
const depNames = const depNames =
name === componentName && externalDeps name === componentName && externalDeps ? externalDeps : entry.dependencies || []
? externalDeps
: entry.dependencies || [];
const deps: Record<string, any> = {}; const deps: Record<string, any> = {}
for (const dep of depNames) { for (const dep of depNames) {
deps[dep] = compileWithDependencies(dep); deps[dep] = compileWithDependencies(dep)
} }
const comp = compileComponent(entry.jsx_code, { const comp = compileComponent(entry.jsx_code, {
React, React,
...staticComponents, ...staticComponents,
...deps, ...deps,
}); })
compiled[name] = comp; compiled[name] = comp
return comp; return comp
}; }
try { try {
const RootComponent = compileWithDependencies(componentName); const RootComponent = compileWithDependencies(componentName)
setComponent(() => RootComponent); setComponent(() => RootComponent)
} catch (err: any) { } catch (err: any) {
console.error("Compilation error:", err); console.error('Compilation error:', err)
} }
}, [componentName, externalDeps, components, getComponentByName]); }, [componentName, externalDeps, components, getComponentByName])
if (!Component) return <div>Yükleniyor...</div>; if (!Component) return <div>Yükleniyor...</div>
return ( return (
<ErrorBoundary key={componentName}> <ErrorBoundary key={componentName}>
<Component /> <Component />
</ErrorBoundary> </ErrorBoundary>
); )
}; }
export default DynamicRenderer; export default DynamicRenderer

View file

@ -2,20 +2,20 @@ import React, { useState } from 'react'
import { useEntities } from '../../contexts/EntityContext' import { useEntities } from '../../contexts/EntityContext'
import axios from 'axios' import axios from 'axios'
import { import {
Book, FaBook,
Search, FaSearch,
Filter, FaFilter,
Globe, FaGlobe,
Copy, FaCopy,
CheckCircle, FaCheckCircle,
AlertCircle, FaExclamationCircle,
Database, FaDatabase,
Loader2, FaSyncAlt,
Send, FaPaperPlane,
PlusCircle, FaPlusCircle,
Edit3, FaEdit,
Trash2, FaTrash
} from 'lucide-react' } from 'react-icons/fa';
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
interface EndpointType { interface EndpointType {
@ -378,7 +378,7 @@ const ApiManager: React.FC = () => {
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="flex items-center gap-2 bg-blue-100 text-blue-700 px-3 py-1 rounded-full text-sm font-medium"> <div className="flex items-center gap-2 bg-blue-100 text-blue-700 px-3 py-1 rounded-full text-sm font-medium">
<Globe className="w-4 h-4" /> <FaGlobe className="w-4 h-4" />
{translate('::App.DeveloperKit.Endpoint.SwaggerCompatible')} {translate('::App.DeveloperKit.Endpoint.SwaggerCompatible')}
</div> </div>
</div> </div>
@ -397,7 +397,7 @@ const ApiManager: React.FC = () => {
</p> </p>
</div> </div>
<div className="bg-emerald-100 text-emerald-600 p-3 rounded-lg"> <div className="bg-emerald-100 text-emerald-600 p-3 rounded-lg">
<Database className="w-6 h-6" /> <FaDatabase className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -410,7 +410,7 @@ const ApiManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.GET}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.GET}</p>
</div> </div>
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg"> <div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
<Book className="w-6 h-6" /> <FaBook className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -423,7 +423,7 @@ const ApiManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.POST}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.POST}</p>
</div> </div>
<div className="bg-purple-100 text-purple-600 p-3 rounded-lg"> <div className="bg-purple-100 text-purple-600 p-3 rounded-lg">
<PlusCircle className="w-6 h-6" /> <FaPlusCircle className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -436,7 +436,7 @@ const ApiManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.PUT}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.PUT}</p>
</div> </div>
<div className="bg-purple-100 text-purple-600 p-3 rounded-lg"> <div className="bg-purple-100 text-purple-600 p-3 rounded-lg">
<Edit3 className="w-6 h-6" /> <FaEdit className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -449,7 +449,7 @@ const ApiManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.DELETE}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.byMethod.DELETE}</p>
</div> </div>
<div className="bg-purple-100 text-purple-600 p-3 rounded-lg"> <div className="bg-purple-100 text-purple-600 p-3 rounded-lg">
<Trash2 className="w-6 h-6" /> <FaTrash className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -459,7 +459,7 @@ const ApiManager: React.FC = () => {
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm"> <div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
<div className="flex flex-col lg:flex-row gap-4"> <div className="flex flex-col lg:flex-row gap-4">
<div className="flex-1 relative"> <div className="flex-1 relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
<input <input
type="text" type="text"
placeholder={translate('::App.DeveloperKit.Endpoint.SearchPlaceholder')} placeholder={translate('::App.DeveloperKit.Endpoint.SearchPlaceholder')}
@ -470,7 +470,7 @@ const ApiManager: React.FC = () => {
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Filter className="w-5 h-5 text-slate-500" /> <FaFilter className="w-5 h-5 text-slate-500" />
<select <select
value={filterMethod} value={filterMethod}
onChange={(e) => onChange={(e) =>
@ -531,7 +531,7 @@ const ApiManager: React.FC = () => {
</div> </div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<CheckCircle className="w-5 h-5 text-green-500" /> <FaCheckCircle className="w-5 h-5 text-green-500" />
<span className="text-sm text-slate-500">{translate('::App.DeveloperKit.Endpoint.Active')}</span> <span className="text-sm text-slate-500">{translate('::App.DeveloperKit.Endpoint.Active')}</span>
</div> </div>
</div> </div>
@ -561,7 +561,7 @@ const ApiManager: React.FC = () => {
className="p-2 text-slate-600 hover:text-slate-900 transition-colors" className="p-2 text-slate-600 hover:text-slate-900 transition-colors"
title={translate('::App.DeveloperKit.Endpoint.CopyUrl')} title={translate('::App.DeveloperKit.Endpoint.CopyUrl')}
> >
<Copy className="w-4 h-4" /> <FaCopy className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -636,7 +636,7 @@ const ApiManager: React.FC = () => {
className="absolute top-2 right-2 p-1 text-slate-600 hover:text-slate-900 transition-colors" className="absolute top-2 right-2 p-1 text-slate-600 hover:text-slate-900 transition-colors"
title={translate('::App.DeveloperKit.Endpoint.CopyRequestBody')} title={translate('::App.DeveloperKit.Endpoint.CopyRequestBody')}
> >
<Copy className="w-3 h-3" /> <FaCopy className="w-3 h-3" />
</button> </button>
</div> </div>
</div> </div>
@ -665,7 +665,7 @@ const ApiManager: React.FC = () => {
className="absolute top-2 right-2 p-1 text-slate-600 hover:text-slate-900 transition-colors" className="absolute top-2 right-2 p-1 text-slate-600 hover:text-slate-900 transition-colors"
title={translate('::App.DeveloperKit.Endpoint.CopyResponse')} title={translate('::App.DeveloperKit.Endpoint.CopyResponse')}
> >
<Copy className="w-3 h-3" /> <FaCopy className="w-3 h-3" />
</button> </button>
</div> </div>
</div> </div>
@ -680,9 +680,9 @@ const ApiManager: React.FC = () => {
className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 disabled:bg-blue-400 disabled:cursor-not-allowed transition-colors text-sm font-medium" className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 disabled:bg-blue-400 disabled:cursor-not-allowed transition-colors text-sm font-medium"
> >
{loadingEndpoints.has(endpoint.id) ? ( {loadingEndpoints.has(endpoint.id) ? (
<Loader2 className="w-4 h-4 animate-spin" /> <FaSyncAlt className="w-4 h-4 animate-spin" />
) : ( ) : (
<Send className="w-4 h-4" /> <FaPaperPlane className="w-4 h-4" />
)} )}
{loadingEndpoints.has(endpoint.id) ? translate('::App.DeveloperKit.Endpoint.SendLoading') : translate('::App.DeveloperKit.Endpoint.SendRequest')} {loadingEndpoints.has(endpoint.id) ? translate('::App.DeveloperKit.Endpoint.SendLoading') : translate('::App.DeveloperKit.Endpoint.SendRequest')}
</button> </button>
@ -711,9 +711,9 @@ const ApiManager: React.FC = () => {
<div className="mt-6 p-4 bg-slate-100 rounded-lg"> <div className="mt-6 p-4 bg-slate-100 rounded-lg">
<div className="flex items-center gap-2 mb-3"> <div className="flex items-center gap-2 mb-3">
{testResults[endpoint.id].success ? ( {testResults[endpoint.id].success ? (
<CheckCircle className="w-5 h-5 text-green-500" /> <FaCheckCircle className="w-5 h-5 text-green-500" />
) : ( ) : (
<AlertCircle className="w-5 h-5 text-red-500" /> <FaExclamationCircle className="w-5 h-5 text-red-500" />
)} )}
<h5 className="font-semibold text-slate-900"> <h5 className="font-semibold text-slate-900">
{translate('::App.DeveloperKit.Endpoint.TestResultLabel')} ({testResults[endpoint.id].status}) {translate('::App.DeveloperKit.Endpoint.TestResultLabel')} ({testResults[endpoint.id].status})
@ -748,7 +748,7 @@ const ApiManager: React.FC = () => {
className="absolute top-2 right-2 p-1 text-slate-600 hover:text-slate-900 transition-colors" className="absolute top-2 right-2 p-1 text-slate-600 hover:text-slate-900 transition-colors"
title={translate('::App.DeveloperKit.Endpoint.CopyResult')} title={translate('::App.DeveloperKit.Endpoint.CopyResult')}
> >
<Copy className="w-3 h-3" /> <FaCopy className="w-3 h-3" />
</button> </button>
</div> </div>
</div> </div>
@ -762,7 +762,7 @@ const ApiManager: React.FC = () => {
<div className="text-center py-12"> <div className="text-center py-12">
<div className="max-w-md mx-auto"> <div className="max-w-md mx-auto">
<div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4"> <div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4">
<Book className="w-8 h-8 text-slate-500" /> <FaBook className="w-8 h-8 text-slate-500" />
</div> </div>
<h3 className="text-lg font-medium text-slate-900 mb-2"> <h3 className="text-lg font-medium text-slate-900 mb-2">
{searchTerm || filterMethod !== 'all' {searchTerm || filterMethod !== 'all'

View file

@ -1,5 +1,5 @@
import { useState, useEffect, useCallback } from 'react' import { useState, useEffect, useCallback } from 'react'
import { PanelTop as Panels } from 'lucide-react' import { FaThLarge } from 'react-icons/fa';
import { import {
parseReactCode, parseReactCode,
updateComponentProp, updateComponentProp,
@ -622,7 +622,7 @@ function CodeLayout() {
className="flex items-center space-x-2 px-3 py-2 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors" className="flex items-center space-x-2 px-3 py-2 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
title="Panel Manager" title="Panel Manager"
> >
<Panels className="w-4 h-4 text-gray-600" /> <FaThLarge className="w-4 h-4 text-gray-600" />
<span className="text-sm text-gray-600">Panels</span> <span className="text-sm text-gray-600">Panels</span>
</button> </button>
</div> </div>

View file

@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback } from 'react' import React, { useState, useEffect, useCallback } from 'react'
import { useParams, useNavigate } from 'react-router-dom' import { useParams, useNavigate } from 'react-router-dom'
import { useComponents } from '../../contexts/ComponentContext' import { useComponents } from '../../contexts/ComponentContext'
import { Save, ArrowLeft, AlertCircle, RefreshCw } from 'lucide-react' import { FaRegSave, FaArrowLeft, FaExclamationCircle, FaSync } from 'react-icons/fa';
import { parseReactCode } from '../../utils/codeParser' import { parseReactCode } from '../../utils/codeParser'
import ComponentPreview from '../../components/componentEditor/ComponentPreview' import ComponentPreview from '../../components/componentEditor/ComponentPreview'
import { EditorState } from '../../@types/componentInfo' import { EditorState } from '../../@types/componentInfo'
@ -143,7 +143,7 @@ const ComponentEditor: React.FC = () => {
return ( return (
<div className="h-screen flex items-center justify-center"> <div className="h-screen flex items-center justify-center">
<div className="text-center"> <div className="text-center">
<RefreshCw className="w-8 h-8 text-blue-500 animate-spin mx-auto mb-3" /> <FaSync className="w-8 h-8 text-blue-500 animate-spin mx-auto mb-3" />
<p className="text-slate-600"> <p className="text-slate-600">
{translate('::App.DeveloperKit.ComponentEditor.Loading')} {translate('::App.DeveloperKit.ComponentEditor.Loading')}
</p> </p>
@ -162,7 +162,7 @@ const ComponentEditor: React.FC = () => {
onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKitComponents)} onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKitComponents)}
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors" className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
> >
<ArrowLeft className="w-4 h-4" /> <FaArrowLeft className="w-4 h-4" />
{translate('::App.DeveloperKit.ComponentEditor.Back')} {translate('::App.DeveloperKit.ComponentEditor.Back')}
</button> </button>
</div> </div>
@ -221,7 +221,7 @@ const ComponentEditor: React.FC = () => {
disabled={isSaving || !name.trim()} disabled={isSaving || !name.trim()}
className="flex items-center gap-2 bg-yellow-600 text-white px-4 py-2 rounded-lg hover:bg-yellow-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm" className="flex items-center gap-2 bg-yellow-600 text-white px-4 py-2 rounded-lg hover:bg-yellow-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm"
> >
<Save className="w-4 h-4" /> <FaRegSave className="w-4 h-4" />
{isSaving {isSaving
? translate('::App.DeveloperKit.ComponentEditor.Saving') ? translate('::App.DeveloperKit.ComponentEditor.Saving')
: translate('::App.DeveloperKit.ComponentEditor.Save')} : translate('::App.DeveloperKit.ComponentEditor.Save')}
@ -237,7 +237,7 @@ const ComponentEditor: React.FC = () => {
<div className="mb-4 bg-red-50 border border-red-200 rounded-lg p-4"> <div className="mb-4 bg-red-50 border border-red-200 rounded-lg p-4">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="bg-red-100 rounded p-1"> <div className="bg-red-100 rounded p-1">
<AlertCircle className="w-4 h-4 text-red-600" /> <FaExclamationCircle className="w-4 h-4 text-red-600" />
</div> </div>
<div className="flex-1"> <div className="flex-1">
<p className="text-sm text-red-800 font-medium mb-2"> <p className="text-sm text-red-800 font-medium mb-2">

View file

@ -2,19 +2,18 @@ import React, { useState } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { useComponents } from '../../contexts/ComponentContext' import { useComponents } from '../../contexts/ComponentContext'
import { import {
Plus, FaPlus,
Search, FaSearch,
Edit, FaRegEdit,
Trash2, FaTrashAlt,
Eye, FaEye,
EyeOff, FaEyeSlash,
Filter, FaFilter,
Calendar, FaCalendarAlt,
Puzzle, FaPuzzlePiece,
CheckCircle, FaCheckCircle,
XCircle, FaTimesCircle,
View, } from 'react-icons/fa';
} from 'lucide-react'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -33,21 +32,21 @@ const ComponentManager: React.FC = () => {
{ {
name: translate('::App.DeveloperKit.Component.Total'), name: translate('::App.DeveloperKit.Component.Total'),
value: totalComponents, value: totalComponents,
icon: Puzzle, icon: FaPuzzlePiece,
color: 'text-purple-600', color: 'text-purple-600',
bgColor: 'bg-purple-100', bgColor: 'bg-purple-100',
}, },
{ {
name: translate('::App.DeveloperKit.Component.Active'), name: translate('::App.DeveloperKit.Component.Active'),
value: activeComponents, value: activeComponents,
icon: CheckCircle, icon: FaCheckCircle,
color: 'text-emerald-600', color: 'text-emerald-600',
bgColor: 'bg-emerald-100', bgColor: 'bg-emerald-100',
}, },
{ {
name: translate('::App.DeveloperKit.Component.Inactive'), name: translate('::App.DeveloperKit.Component.Inactive'),
value: inactiveComponents, value: inactiveComponents,
icon: XCircle, icon: FaTimesCircle,
color: 'text-slate-600', color: 'text-slate-600',
bgColor: 'bg-slate-100', bgColor: 'bg-slate-100',
}, },
@ -100,7 +99,7 @@ const ComponentManager: React.FC = () => {
to={ROUTES_ENUM.protected.saas.developerKitComponentsNew} to={ROUTES_ENUM.protected.saas.developerKitComponentsNew}
className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors" className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
{translate('::App.DeveloperKit.Component.New')} {translate('::App.DeveloperKit.Component.New')}
</Link> </Link>
</div> </div>
@ -126,7 +125,7 @@ const ComponentManager: React.FC = () => {
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6"> <div className="bg-white rounded-lg border border-slate-200 p-6 mb-6">
<div className="flex flex-col sm:flex-row gap-4"> <div className="flex flex-col sm:flex-row gap-4">
<div className="flex-1 relative"> <div className="flex-1 relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
<input <input
type="text" type="text"
placeholder={translate('::App.DeveloperKit.Component.SearchPlaceholder')} placeholder={translate('::App.DeveloperKit.Component.SearchPlaceholder')}
@ -136,7 +135,7 @@ const ComponentManager: React.FC = () => {
/> />
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Filter className="w-5 h-5 text-slate-500" /> <FaFilter className="w-5 h-5 text-slate-500" />
<select <select
value={filterActive} value={filterActive}
onChange={(e) => setFilterActive(e.target.value as 'all' | 'active' | 'inactive')} onChange={(e) => setFilterActive(e.target.value as 'all' | 'active' | 'inactive')}
@ -195,7 +194,7 @@ const ComponentManager: React.FC = () => {
)} )}
<div className="flex items-center gap-4 text-xs text-slate-500"> <div className="flex items-center gap-4 text-xs text-slate-500">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Calendar className="w-3 h-3" /> <FaCalendarAlt className="w-3 h-3" />
<span> <span>
{component.lastModificationTime {component.lastModificationTime
? new Date(component.lastModificationTime).toLocaleDateString() ? new Date(component.lastModificationTime).toLocaleDateString()
@ -231,12 +230,12 @@ const ComponentManager: React.FC = () => {
> >
{component.isActive ? ( {component.isActive ? (
<> <>
<Eye className="w-3 h-3" /> <FaEye className="w-3 h-3" />
{translate('::App.DeveloperKit.Component.Active')} {translate('::App.DeveloperKit.Component.Active')}
</> </>
) : ( ) : (
<> <>
<EyeOff className="w-3 h-3" /> <FaEyeSlash className="w-3 h-3" />
{translate('::App.DeveloperKit.Component.Inactive')} {translate('::App.DeveloperKit.Component.Inactive')}
</> </>
)} )}
@ -252,7 +251,7 @@ const ComponentManager: React.FC = () => {
className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors" className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
title={translate('::App.DeveloperKit.Component.Edit')} title={translate('::App.DeveloperKit.Component.Edit')}
> >
<Edit className="w-4 h-4" /> <FaRegEdit className="w-4 h-4" />
</Link> </Link>
<Link <Link
to={ROUTES_ENUM.protected.saas.developerKitComponentsView.replace( to={ROUTES_ENUM.protected.saas.developerKitComponentsView.replace(
@ -262,14 +261,14 @@ const ComponentManager: React.FC = () => {
className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors" className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
title={translate('::App.DeveloperKit.Component.View')} title={translate('::App.DeveloperKit.Component.View')}
> >
<View className="w-4 h-4" /> <FaEye className="w-4 h-4" />
</Link> </Link>
<button <button
onClick={() => handleDelete(component.id, component.name)} onClick={() => handleDelete(component.id, component.name)}
className="p-2 text-slate-600 hover:text-red-600 hover:bg-red-50 rounded transition-colors" className="p-2 text-slate-600 hover:text-red-600 hover:bg-red-50 rounded transition-colors"
title={translate('::App.DeveloperKit.Component.Delete')} title={translate('::App.DeveloperKit.Component.Delete')}
> >
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -281,7 +280,7 @@ const ComponentManager: React.FC = () => {
<div className="text-center py-12"> <div className="text-center py-12">
<div className="max-w-md mx-auto"> <div className="max-w-md mx-auto">
<div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4"> <div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4">
<Plus className="w-8 h-8 text-slate-500" /> <FaPlus className="w-8 h-8 text-slate-500" />
</div> </div>
<h3 className="text-lg font-medium text-slate-900 mb-2"> <h3 className="text-lg font-medium text-slate-900 mb-2">
{searchTerm || filterActive !== 'all' {searchTerm || filterActive !== 'all'
@ -298,7 +297,7 @@ const ComponentManager: React.FC = () => {
to={ROUTES_ENUM.protected.saas.developerKitComponentsNew} to={ROUTES_ENUM.protected.saas.developerKitComponentsNew}
className="inline-flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors" className="inline-flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
{translate('::App.DeveloperKit.Component.Empty.Initial.Action')} {translate('::App.DeveloperKit.Component.Empty.Initial.Action')}
</Link> </Link>
)} )}

View file

@ -4,18 +4,19 @@ import { useComponents } from "../../contexts/ComponentContext";
import { useEntities } from "../../contexts/EntityContext"; import { useEntities } from "../../contexts/EntityContext";
import { useSystemHealth } from "../../utils/hooks/useDeveloperKit"; import { useSystemHealth } from "../../utils/hooks/useDeveloperKit";
import { import {
Database, FaDatabase,
Zap, FaBolt,
Server, FaServer,
Puzzle, FaPuzzlePiece,
Activity, FaCog,
Code, FaChartLine,
CheckCircle, FaCode,
ArrowRight, FaCheckCircle,
AlertCircle, FaArrowRight,
Wifi, FaExclamationCircle,
WifiOff, FaWifi,
} from "lucide-react"; FaWindowClose
} from 'react-icons/fa';
import { ROUTES_ENUM } from "@/routes/route.constant"; import { ROUTES_ENUM } from "@/routes/route.constant";
import { useLocalization } from "@/utils/hooks/useLocalization"; import { useLocalization } from "@/utils/hooks/useLocalization";
@ -30,7 +31,7 @@ const Dashboard: React.FC = () => {
name: translate('::App.DeveloperKit.Dashboard.Stats.Entities'), name: translate('::App.DeveloperKit.Dashboard.Stats.Entities'),
value: entities.filter((e) => e.isActive).length, value: entities.filter((e) => e.isActive).length,
total: entities.length, total: entities.length,
icon: Database, icon: FaDatabase,
color: "text-blue-600", color: "text-blue-600",
bgColor: "bg-blue-100", bgColor: "bg-blue-100",
href: ROUTES_ENUM.protected.saas.developerKitEntities, href: ROUTES_ENUM.protected.saas.developerKitEntities,
@ -39,7 +40,7 @@ const Dashboard: React.FC = () => {
name: translate('::App.DeveloperKit.Dashboard.Stats.Migrations'), name: translate('::App.DeveloperKit.Dashboard.Stats.Migrations'),
value: migrations.filter((m) => m.status === "pending").length, value: migrations.filter((m) => m.status === "pending").length,
total: migrations.length, total: migrations.length,
icon: Zap, icon: FaBolt,
color: "text-yellow-600", color: "text-yellow-600",
bgColor: "bg-yellow-100", bgColor: "bg-yellow-100",
href: ROUTES_ENUM.protected.saas.developerKitMigrations, href: ROUTES_ENUM.protected.saas.developerKitMigrations,
@ -48,7 +49,7 @@ const Dashboard: React.FC = () => {
name: translate('::App.DeveloperKit.Dashboard.Stats.APIs'), name: translate('::App.DeveloperKit.Dashboard.Stats.APIs'),
value: generatedEndpoints.filter((e) => e.isActive).length, value: generatedEndpoints.filter((e) => e.isActive).length,
total: generatedEndpoints.length, total: generatedEndpoints.length,
icon: Server, icon: FaServer,
color: "text-emerald-600", color: "text-emerald-600",
bgColor: "bg-emerald-100", bgColor: "bg-emerald-100",
href: ROUTES_ENUM.protected.saas.developerKitEndpoints, href: ROUTES_ENUM.protected.saas.developerKitEndpoints,
@ -57,7 +58,7 @@ const Dashboard: React.FC = () => {
name: translate('::App.DeveloperKit.Dashboard.Stats.Components'), name: translate('::App.DeveloperKit.Dashboard.Stats.Components'),
value: components?.filter((c) => c.isActive).length, value: components?.filter((c) => c.isActive).length,
total: components?.length, total: components?.length,
icon: Puzzle, icon: FaPuzzlePiece,
color: "text-purple-600", color: "text-purple-600",
bgColor: "bg-purple-100", bgColor: "bg-purple-100",
href: ROUTES_ENUM.protected.saas.developerKitComponents, href: ROUTES_ENUM.protected.saas.developerKitComponents,
@ -69,7 +70,7 @@ const Dashboard: React.FC = () => {
step: 1, step: 1,
title: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity'), title: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity'),
description: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity.Desc'), description: translate('::App.DeveloperKit.Dashboard.Flow.CreateEntity.Desc'),
icon: Database, icon: FaDatabase,
color: "bg-blue-600", color: "bg-blue-600",
href: ROUTES_ENUM.protected.saas.developerKitEntitiesNew, href: ROUTES_ENUM.protected.saas.developerKitEntitiesNew,
status: "ready", status: "ready",
@ -78,7 +79,7 @@ const Dashboard: React.FC = () => {
step: 2, step: 2,
title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration'), title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration'),
description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration.Desc'), description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateMigration.Desc'),
icon: Zap, icon: FaBolt,
color: "bg-yellow-600", color: "bg-yellow-600",
href: ROUTES_ENUM.protected.saas.developerKitMigrations, href: ROUTES_ENUM.protected.saas.developerKitMigrations,
status: entities.some((e) => e.migrationStatus === "pending") status: entities.some((e) => e.migrationStatus === "pending")
@ -89,7 +90,7 @@ const Dashboard: React.FC = () => {
step: 3, step: 3,
title: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration'), title: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration'),
description: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration.Desc'), description: translate('::App.DeveloperKit.Dashboard.Flow.ApplyMigration.Desc'),
icon: CheckCircle, icon: FaCheckCircle,
color: "bg-green-600", color: "bg-green-600",
href: ROUTES_ENUM.protected.saas.developerKitMigrations, href: ROUTES_ENUM.protected.saas.developerKitMigrations,
status: migrations.some((m) => m.status === "pending") status: migrations.some((m) => m.status === "pending")
@ -100,7 +101,7 @@ const Dashboard: React.FC = () => {
step: 4, step: 4,
title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI'), title: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI'),
description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI.Desc'), description: translate('::App.DeveloperKit.Dashboard.Flow.GenerateAPI.Desc'),
icon: Server, icon: FaServer,
color: "bg-emerald-600", color: "bg-emerald-600",
href: ROUTES_ENUM.protected.saas.developerKitEndpoints, href: ROUTES_ENUM.protected.saas.developerKitEndpoints,
status: "ready", status: "ready",
@ -109,7 +110,7 @@ const Dashboard: React.FC = () => {
step: 5, step: 5,
title: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent'), title: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent'),
description: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent.Desc'), description: translate('::App.DeveloperKit.Dashboard.Flow.BuildComponent.Desc'),
icon: Puzzle, icon: FaPuzzlePiece,
color: "bg-purple-600", color: "bg-purple-600",
href: ROUTES_ENUM.protected.saas.developerKitComponentsNew, href: ROUTES_ENUM.protected.saas.developerKitComponentsNew,
status: "ready", status: "ready",
@ -132,23 +133,23 @@ const Dashboard: React.FC = () => {
].slice(0, 3); ].slice(0, 3);
const systemHealth = [ const systemHealth = [
{ name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Frontend'), status: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'), icon: Code }, { name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Frontend'), status: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'), icon: FaCode },
{ {
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Backend'), name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Backend'),
status: isOnline ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy') : translate('::App.DeveloperKit.Dashboard.SystemHealth.Offline'), status: isOnline ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy') : translate('::App.DeveloperKit.Dashboard.SystemHealth.Offline'),
icon: Server, icon: FaServer,
}, },
{ {
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Database'), name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Database'),
status: isOnline ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy') : translate('::App.DeveloperKit.Dashboard.SystemHealth.Unknown'), status: isOnline ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy') : translate('::App.DeveloperKit.Dashboard.SystemHealth.Unknown'),
icon: Database, icon: FaDatabase,
}, },
{ {
name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Migrations'), name: translate('::App.DeveloperKit.Dashboard.SystemHealth.Migrations'),
status: migrations.some((m) => m.status === "failed") status: migrations.some((m) => m.status === "failed")
? translate('::App.DeveloperKit.Dashboard.SystemHealth.Warning') ? translate('::App.DeveloperKit.Dashboard.SystemHealth.Warning')
: translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'), : translate('::App.DeveloperKit.Dashboard.SystemHealth.Healthy'),
icon: Zap, icon: FaBolt,
}, },
]; ];
@ -183,12 +184,12 @@ const Dashboard: React.FC = () => {
/> />
{isOnline ? ( {isOnline ? (
<> <>
<Wifi className="w-4 h-4" /> <FaWifi className="w-4 h-4" />
{translate('::App.DeveloperKit.Dashboard.SystemHealth.Online')} {translate('::App.DeveloperKit.Dashboard.SystemHealth.Online')}
</> </>
) : ( ) : (
<> <>
<WifiOff className="w-4 h-4" /> <FaWindowClose className="w-4 h-4" />
{translate('::App.DeveloperKit.Dashboard.SystemHealth.OfflineStatus')} {translate('::App.DeveloperKit.Dashboard.SystemHealth.OfflineStatus')}
</> </>
)} )}
@ -212,7 +213,7 @@ const Dashboard: React.FC = () => {
> >
<Icon className="w-6 h-6" /> <Icon className="w-6 h-6" />
</div> </div>
<ArrowRight className="w-4 h-4 text-slate-400 group-hover:text-slate-600 transition-colors" /> <FaArrowRight className="w-4 h-4 text-slate-400 group-hover:text-slate-600 transition-colors" />
</div> </div>
<div> <div>
<p className="text-sm font-medium text-slate-600"> <p className="text-sm font-medium text-slate-600">
@ -233,7 +234,7 @@ const Dashboard: React.FC = () => {
{/* Development Flow */} {/* Development Flow */}
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-8"> <div className="bg-white rounded-xl shadow-sm border border-slate-200 p-8">
<div className="flex items-center gap-2 mb-6"> <div className="flex items-center gap-2 mb-6">
<Activity className="w-6 h-6 text-blue-600" /> <FaCog className="w-6 h-6 text-blue-600" />
<h2 className="text-xl font-semibold text-slate-900"> <h2 className="text-xl font-semibold text-slate-900">
{translate('::App.DeveloperKit.Dashboard.Flow.Title')} {translate('::App.DeveloperKit.Dashboard.Flow.Title')}
</h2> </h2>
@ -260,7 +261,7 @@ const Dashboard: React.FC = () => {
{flow.status === "action-needed" && ( {flow.status === "action-needed" && (
<div className="absolute -top-2 -right-2"> <div className="absolute -top-2 -right-2">
<div className="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center"> <div className="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center">
<AlertCircle className="w-4 h-4" /> <FaExclamationCircle className="w-4 h-4" />
</div> </div>
</div> </div>
)} )}
@ -268,7 +269,7 @@ const Dashboard: React.FC = () => {
{index < developmentFlow.length - 1 && ( {index < developmentFlow.length - 1 && (
<div className="hidden lg:block absolute top-1/2 -right-3 transform -translate-y-1/2"> <div className="hidden lg:block absolute top-1/2 -right-3 transform -translate-y-1/2">
<ArrowRight className="w-6 h-6 text-slate-300" /> <FaArrowRight className="w-6 h-6 text-slate-300" />
</div> </div>
)} )}
</Link> </Link>
@ -281,7 +282,7 @@ const Dashboard: React.FC = () => {
{/* System Health */} {/* System Health */}
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6"> <div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
<div className="flex items-center gap-2 mb-4"> <div className="flex items-center gap-2 mb-4">
<Activity className="w-5 h-5 text-green-500" /> <FaCog className="w-5 h-5 text-green-500" />
<h3 className="text-lg font-semibold text-slate-900"> <h3 className="text-lg font-semibold text-slate-900">
{translate('::App.DeveloperKit.Dashboard.SystemHealth.Title') } {translate('::App.DeveloperKit.Dashboard.SystemHealth.Title') }
</h3> </h3>
@ -374,14 +375,14 @@ const Dashboard: React.FC = () => {
to={ROUTES_ENUM.protected.saas.developerKitEntitiesEdit.replace(':id', entity.id)} to={ROUTES_ENUM.protected.saas.developerKitEntitiesEdit.replace(':id', entity.id)}
className="text-blue-600 hover:text-blue-700" className="text-blue-600 hover:text-blue-700"
> >
<Database className="w-4 h-4" /> <FaDatabase className="w-4 h-4" />
</Link> </Link>
</div> </div>
</div> </div>
)) ))
) : ( ) : (
<div className="text-center py-8"> <div className="text-center py-8">
<Database className="w-12 h-12 text-slate-300 mx-auto mb-2" /> <FaDatabase className="w-12 h-12 text-slate-300 mx-auto mb-2" />
<p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Entity')}</p> <p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Entity')}</p>
<Link <Link
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew} to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
@ -437,14 +438,14 @@ const Dashboard: React.FC = () => {
to={ROUTES_ENUM.protected.saas.developerKitMigrations} to={ROUTES_ENUM.protected.saas.developerKitMigrations}
className="text-yellow-600 hover:text-yellow-700" className="text-yellow-600 hover:text-yellow-700"
> >
<Zap className="w-4 h-4" /> <FaBolt className="w-4 h-4" />
</Link> </Link>
</div> </div>
</div> </div>
)) ))
) : ( ) : (
<div className="text-center py-8"> <div className="text-center py-8">
<Zap className="w-12 h-12 text-slate-300 mx-auto mb-2" /> <FaBolt className="w-12 h-12 text-slate-300 mx-auto mb-2" />
<p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Migration')}</p> <p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Migration')}</p>
<Link <Link
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew} to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
@ -508,14 +509,14 @@ const Dashboard: React.FC = () => {
to="/docs" to="/docs"
className="text-emerald-600 hover:text-emerald-700" className="text-emerald-600 hover:text-emerald-700"
> >
<Server className="w-4 h-4" /> <FaServer className="w-4 h-4" />
</Link> </Link>
</div> </div>
</div> </div>
)) ))
) : ( ) : (
<div className="text-center py-8"> <div className="text-center py-8">
<Server className="w-12 h-12 text-slate-300 mx-auto mb-2" /> <FaServer className="w-12 h-12 text-slate-300 mx-auto mb-2" />
<p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Endpoint')}</p> <p className="text-slate-500 mb-2">{translate('::App.DeveloperKit.Dashboard.Empty.Endpoint')}</p>
<Link <Link
to={ROUTES_ENUM.protected.saas.developerKitEndpointsNew} to={ROUTES_ENUM.protected.saas.developerKitEndpointsNew}

View file

@ -1,7 +1,14 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { useParams, useNavigate } from 'react-router-dom' import { useParams, useNavigate } from 'react-router-dom'
import { useEntities, EntityFieldType } from '../../contexts/EntityContext' import { useEntities, EntityFieldType } from '../../contexts/EntityContext'
import { Save, ArrowLeft, Plus, Trash2, Database, HelpCircle } from 'lucide-react' import {
FaSave,
FaArrowLeft,
FaPlus,
FaTrashAlt,
FaDatabase,
FaQuestionCircle
} from 'react-icons/fa';
import { CreateUpdateCustomEntityFieldDto, CustomEntityField } from '@/proxy/developerKit/models' import { CreateUpdateCustomEntityFieldDto, CustomEntityField } from '@/proxy/developerKit/models'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -172,12 +179,12 @@ const EntityEditor: React.FC = () => {
onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKitEntities)} onClick={() => navigate(ROUTES_ENUM.protected.saas.developerKitEntities)}
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors" className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
> >
<ArrowLeft className="w-4 h-4" /> <FaArrowLeft className="w-4 h-4" />
{translate('::App.DeveloperKit.EntityEditor.Back')} {translate('::App.DeveloperKit.EntityEditor.Back')}
</button> </button>
<div className="h-6 w-px bg-slate-300" /> <div className="h-6 w-px bg-slate-300" />
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Database className="w-6 h-6 text-blue-600" /> <FaDatabase className="w-6 h-6 text-blue-600" />
<h1 className="text-xl font-semibold text-slate-900"> <h1 className="text-xl font-semibold text-slate-900">
{isEditing {isEditing
? translate('::App.DeveloperKit.EntityEditor.Title.Edit') ? translate('::App.DeveloperKit.EntityEditor.Title.Edit')
@ -189,12 +196,12 @@ const EntityEditor: React.FC = () => {
{/* Help Tooltip */} {/* Help Tooltip */}
<div className="relative group"> <div className="relative group">
<button className="p-2 text-slate-400 hover:text-slate-600 transition-colors"> <button className="p-2 text-slate-400 hover:text-slate-600 transition-colors">
<HelpCircle className="w-4 h-4" /> <FaQuestionCircle className="w-4 h-4" />
</button> </button>
<div className="absolute right-0 top-full mt-2 w-96 bg-slate-900 text-white text-sm rounded-lg p-4 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-xl"> <div className="absolute right-0 top-full mt-2 w-96 bg-slate-900 text-white text-sm rounded-lg p-4 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-xl">
<div className="absolute -top-1 right-4 w-2 h-2 bg-slate-900 rotate-45"></div> <div className="absolute -top-1 right-4 w-2 h-2 bg-slate-900 rotate-45"></div>
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2">
<Database className="w-4 h-4 text-blue-400" /> <FaDatabase className="w-4 h-4 text-blue-400" />
<h4 className="font-semibold text-blue-200">{translate('::App.DeveloperKit.EntityEditor.Tooltip.Title')}</h4> <h4 className="font-semibold text-blue-200">{translate('::App.DeveloperKit.EntityEditor.Tooltip.Title')}</h4>
</div> </div>
<p className="text-slate-300 leading-relaxed"> <p className="text-slate-300 leading-relaxed">
@ -208,7 +215,7 @@ const EntityEditor: React.FC = () => {
disabled={isSaving || !name.trim() || !displayName.trim() || !tableName.trim()} disabled={isSaving || !name.trim() || !displayName.trim() || !tableName.trim()}
className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm" className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed shadow-sm"
> >
<Save className="w-4 h-4" /> <FaSave className="w-4 h-4" />
{isSaving ? translate('::App.DeveloperKit.EntityEditor.Saving') : translate('::App.DeveloperKit.EntityEditor.Save')} {isSaving ? translate('::App.DeveloperKit.EntityEditor.Saving') : translate('::App.DeveloperKit.EntityEditor.Save')}
</button> </button>
</div> </div>
@ -370,7 +377,7 @@ const EntityEditor: React.FC = () => {
onClick={addField} onClick={addField}
className="flex items-center gap-2 bg-blue-600 text-white px-3 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm" className="flex items-center gap-2 bg-blue-600 text-white px-3 py-2 rounded-lg hover:bg-blue-700 transition-colors text-sm"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
{translate('::App.DeveloperKit.EntityEditor.AddField')} {translate('::App.DeveloperKit.EntityEditor.AddField')}
</button> </button>
</div> </div>
@ -484,7 +491,7 @@ const EntityEditor: React.FC = () => {
className="p-2 text-slate-600 hover:text-red-600 hover:bg-red-50 rounded transition-colors" className="p-2 text-slate-600 hover:text-red-600 hover:bg-red-50 rounded transition-colors"
title={translate('::App.DeveloperKit.EntityEditor.RemoveField')} title={translate('::App.DeveloperKit.EntityEditor.RemoveField')}
> >
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -494,7 +501,7 @@ const EntityEditor: React.FC = () => {
{fields.length === 0 && ( {fields.length === 0 && (
<div className="text-center py-8 text-slate-500"> <div className="text-center py-8 text-slate-500">
<Database className="w-12 h-12 mx-auto mb-2 text-slate-300" /> <FaDatabase className="w-12 h-12 mx-auto mb-2 text-slate-300" />
<p>{translate('::App.DeveloperKit.EntityEditor.NoFields')}</p> <p>{translate('::App.DeveloperKit.EntityEditor.NoFields')}</p>
<p className="text-sm">{translate('::App.DeveloperKit.EntityEditor.NoFieldsDescription')}</p> <p className="text-sm">{translate('::App.DeveloperKit.EntityEditor.NoFieldsDescription')}</p>
</div> </div>

View file

@ -1,20 +1,20 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useEntities } from '../../contexts/EntityContext'; import { useEntities } from '../../contexts/EntityContext';
import { import {
Plus, FaPlus,
Search, FaSearch,
Edit, FaEdit,
Trash2, FaTrashAlt,
Eye, FaEye,
EyeOff, FaEyeSlash,
Filter, FaFilter,
Calendar, FaCalendarAlt,
Database, FaDatabase,
CheckCircle, FaCheckCircle,
Table, FaTable,
Zap FaBolt
} from 'lucide-react'; } from 'react-icons/fa';
import { ROUTES_ENUM } from '@/routes/route.constant'; import { ROUTES_ENUM } from '@/routes/route.constant';
import { useLocalization } from '@/utils/hooks/useLocalization'; import { useLocalization } from '@/utils/hooks/useLocalization';
@ -75,7 +75,7 @@ const EntityManager: React.FC = () => {
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew} to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md" className="flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
{translate('::App.DeveloperKit.Entity.NewEntity')} {translate('::App.DeveloperKit.Entity.NewEntity')}
</Link> </Link>
</div> </div>
@ -89,7 +89,7 @@ const EntityManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p>
</div> </div>
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg"> <div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
<Database className="w-6 h-6" /> <FaDatabase className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -105,7 +105,7 @@ const EntityManager: React.FC = () => {
</p> </p>
</div> </div>
<div className="bg-green-100 text-green-600 p-3 rounded-lg"> <div className="bg-green-100 text-green-600 p-3 rounded-lg">
<CheckCircle className="w-6 h-6" /> <FaCheckCircle className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -116,7 +116,7 @@ const EntityManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.migrationsPending}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.migrationsPending}</p>
</div> </div>
<div className="bg-purple-100 text-purple-600 p-3 rounded-lg"> <div className="bg-purple-100 text-purple-600 p-3 rounded-lg">
<Zap className="w-6 h-6" /> <FaBolt className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -127,7 +127,7 @@ const EntityManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.endpointsApplied}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.endpointsApplied}</p>
</div> </div>
<div className="bg-emerald-100 text-emerald-600 p-3 rounded-lg"> <div className="bg-emerald-100 text-emerald-600 p-3 rounded-lg">
<Zap className="w-6 h-6" /> <FaBolt className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -137,7 +137,7 @@ const EntityManager: React.FC = () => {
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm"> <div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
<div className="flex flex-col lg:flex-row gap-4"> <div className="flex flex-col lg:flex-row gap-4">
<div className="flex-1 relative"> <div className="flex-1 relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
<input <input
type="text" type="text"
placeholder={translate('::App.DeveloperKit.Entity.SearchPlaceholder')} placeholder={translate('::App.DeveloperKit.Entity.SearchPlaceholder')}
@ -148,7 +148,7 @@ const EntityManager: React.FC = () => {
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Filter className="w-5 h-5 text-slate-500" /> <FaFilter className="w-5 h-5 text-slate-500" />
<select <select
value={filterActive} value={filterActive}
onChange={(e) => setFilterActive(e.target.value as 'all' | 'active' | 'inactive')} onChange={(e) => setFilterActive(e.target.value as 'all' | 'active' | 'inactive')}
@ -174,7 +174,7 @@ const EntityManager: React.FC = () => {
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center gap-3 mb-2"> <div className="flex items-center gap-3 mb-2">
<div className="bg-blue-100 text-blue-600 p-2 rounded-lg"> <div className="bg-blue-100 text-blue-600 p-2 rounded-lg">
<Table className="w-5 h-5" /> <FaTable className="w-5 h-5" />
</div> </div>
<div> <div>
<h3 className="text-lg font-semibold text-slate-900"> <h3 className="text-lg font-semibold text-slate-900">
@ -191,13 +191,13 @@ const EntityManager: React.FC = () => {
)} )}
<div className="flex items-center gap-4 text-xs text-slate-500 mb-3"> <div className="flex items-center gap-4 text-xs text-slate-500 mb-3">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Calendar className="w-3 h-3" /> <FaCalendarAlt className="w-3 h-3" />
<span> <span>
{translate('::App.DeveloperKit.Entity.Updated')}: {entity.lastModificationTime ? new Date(entity.lastModificationTime).toLocaleDateString() : 'Never'} {translate('::App.DeveloperKit.Entity.Updated')}: {entity.lastModificationTime ? new Date(entity.lastModificationTime).toLocaleDateString() : 'Never'}
</span> </span>
</div> </div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Database className="w-3 h-3" /> <FaDatabase className="w-3 h-3" />
<span>{entity.fields.length} {translate('::App.DeveloperKit.Entity.Fields')}</span> <span>{entity.fields.length} {translate('::App.DeveloperKit.Entity.Fields')}</span>
</div> </div>
</div> </div>
@ -270,12 +270,12 @@ const EntityManager: React.FC = () => {
> >
{entity.isActive ? ( {entity.isActive ? (
<> <>
<Eye className="w-3 h-3" /> <FaEye className="w-3 h-3" />
{translate('::App.DeveloperKit.Entity.Active')} {translate('::App.DeveloperKit.Entity.Active')}
</> </>
) : ( ) : (
<> <>
<EyeOff className="w-3 h-3" /> <FaEyeSlash className="w-3 h-3" />
{translate('::App.DeveloperKit.Entity.Inactive')} {translate('::App.DeveloperKit.Entity.Inactive')}
</> </>
)} )}
@ -287,14 +287,14 @@ const EntityManager: React.FC = () => {
className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors" className="p-2 text-slate-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
title={translate('::App.DeveloperKit.Entity.Edit')} title={translate('::App.DeveloperKit.Entity.Edit')}
> >
<Edit className="w-4 h-4" /> <FaEdit className="w-4 h-4" />
</Link> </Link>
<button <button
onClick={() => handleDelete(entity.id, entity.displayName)} onClick={() => handleDelete(entity.id, entity.displayName)}
className="p-2 text-slate-600 hover:text-red-600 hover:bg-red-50 rounded transition-colors" className="p-2 text-slate-600 hover:text-red-600 hover:bg-red-50 rounded transition-colors"
title={translate('::App.DeveloperKit.Entity.Delete')} title={translate('::App.DeveloperKit.Entity.Delete')}
> >
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -307,7 +307,7 @@ const EntityManager: React.FC = () => {
<div className="text-center py-12"> <div className="text-center py-12">
<div className="max-w-md mx-auto"> <div className="max-w-md mx-auto">
<div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4"> <div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4">
<Database className="w-8 h-8 text-slate-500" /> <FaDatabase className="w-8 h-8 text-slate-500" />
</div> </div>
<h3 className="text-lg font-medium text-slate-900 mb-2"> <h3 className="text-lg font-medium text-slate-900 mb-2">
{searchTerm || filterActive !== 'all' ? translate('::App.DeveloperKit.Entity.NoEntitiesFound') : translate('::App.DeveloperKit.Entity.NoEntitiesYet')} {searchTerm || filterActive !== 'all' ? translate('::App.DeveloperKit.Entity.NoEntitiesFound') : translate('::App.DeveloperKit.Entity.NoEntitiesYet')}
@ -323,7 +323,7 @@ const EntityManager: React.FC = () => {
to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew} to={ROUTES_ENUM.protected.saas.developerKitEntitiesNew}
className="inline-flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md" className="inline-flex items-center gap-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors shadow-sm hover:shadow-md"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
{translate('::App.DeveloperKit.Entity.CreateEntity')} {translate('::App.DeveloperKit.Entity.CreateEntity')}
</Link> </Link>
)} )}

View file

@ -2,22 +2,22 @@ import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useEntities } from '../../contexts/EntityContext' import { useEntities } from '../../contexts/EntityContext'
import { import {
Zap, FaBolt,
Search, FaSearch,
Filter, FaFilter,
Calendar, FaCalendarAlt,
Database, FaDatabase,
Play, FaPlay,
CheckCircle, FaCheckCircle,
AlertCircle, FaRegBell,
Clock, FaRegClock,
FileText, FaRegFileAlt,
Download, FaDownload,
Eye, FaEye,
RefreshCw, FaSync,
Trash2, FaTrashAlt,
Plus, FaPlus
} from 'lucide-react' } from 'react-icons/fa';
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -126,13 +126,13 @@ const MigrationManager: React.FC = () => {
const getStatusIcon = (status: string) => { const getStatusIcon = (status: string) => {
switch (status) { switch (status) {
case 'pending': case 'pending':
return Clock return FaRegClock
case 'applied': case 'applied':
return CheckCircle return FaCheckCircle
case 'failed': case 'failed':
return AlertCircle return FaRegBell
default: default:
return Clock return FaRegClock
} }
} }
@ -153,7 +153,7 @@ const MigrationManager: React.FC = () => {
{error && ( {error && (
<div className="mb-6 bg-red-50 border border-red-200 rounded-lg p-4"> <div className="mb-6 bg-red-50 border border-red-200 rounded-lg p-4">
<div className="flex items-center gap-2 text-red-800"> <div className="flex items-center gap-2 text-red-800">
<AlertCircle className="w-5 h-5" /> <FaRegBell className="w-5 h-5" />
<span className="font-medium">Error</span> <span className="font-medium">Error</span>
</div> </div>
<p className="text-red-700 text-sm mt-1">{error}</p> <p className="text-red-700 text-sm mt-1">{error}</p>
@ -169,12 +169,12 @@ const MigrationManager: React.FC = () => {
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="flex items-center gap-2 bg-blue-100 text-blue-700 px-3 py-1 rounded-full text-sm font-medium"> <div className="flex items-center gap-2 bg-blue-100 text-blue-700 px-3 py-1 rounded-full text-sm font-medium">
<Database className="w-4 h-4" /> <FaDatabase className="w-4 h-4" />
{translate('::App.DeveloperKit.Migration.SchemaManagement')} {translate('::App.DeveloperKit.Migration.SchemaManagement')}
</div> </div>
{loading && ( {loading && (
<div className="flex items-center gap-2 bg-yellow-100 text-yellow-700 px-3 py-1 rounded-full text-sm font-medium"> <div className="flex items-center gap-2 bg-yellow-100 text-yellow-700 px-3 py-1 rounded-full text-sm font-medium">
<RefreshCw className="w-4 h-4 animate-spin" /> <FaSync className="w-4 h-4 animate-spin" />
{translate('::App.DeveloperKit.Migration.Loading')} {translate('::App.DeveloperKit.Migration.Loading')}
</div> </div>
)} )}
@ -190,7 +190,7 @@ const MigrationManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.total}</p>
</div> </div>
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg"> <div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
<FileText className="w-6 h-6" /> <FaRegFileAlt className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -201,7 +201,7 @@ const MigrationManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.pending}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.pending}</p>
</div> </div>
<div className="bg-yellow-100 text-yellow-600 p-3 rounded-lg"> <div className="bg-yellow-100 text-yellow-600 p-3 rounded-lg">
<Clock className="w-6 h-6" /> <FaRegClock className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -212,7 +212,7 @@ const MigrationManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.applied}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.applied}</p>
</div> </div>
<div className="bg-green-100 text-green-600 p-3 rounded-lg"> <div className="bg-green-100 text-green-600 p-3 rounded-lg">
<CheckCircle className="w-6 h-6" /> <FaCheckCircle className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -223,7 +223,7 @@ const MigrationManager: React.FC = () => {
<p className="text-2xl font-bold text-slate-900 mt-1">{stats.failed}</p> <p className="text-2xl font-bold text-slate-900 mt-1">{stats.failed}</p>
</div> </div>
<div className="bg-red-100 text-red-600 p-3 rounded-lg"> <div className="bg-red-100 text-red-600 p-3 rounded-lg">
<AlertCircle className="w-6 h-6" /> <FaRegBell className="w-6 h-6" />
</div> </div>
</div> </div>
</div> </div>
@ -234,7 +234,7 @@ const MigrationManager: React.FC = () => {
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-6 mb-6"> <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-6 mb-6">
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
<div className="bg-yellow-100 rounded-lg p-2"> <div className="bg-yellow-100 rounded-lg p-2">
<Zap className="w-6 h-6 text-yellow-600" /> <FaBolt className="w-6 h-6 text-yellow-600" />
</div> </div>
<div className="flex-1"> <div className="flex-1">
<h3 className="text-lg font-semibold text-slate-900 mb-2"> <h3 className="text-lg font-semibold text-slate-900 mb-2">
@ -271,7 +271,7 @@ const MigrationManager: React.FC = () => {
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm"> <div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
<div className="flex flex-col lg:flex-row gap-4"> <div className="flex flex-col lg:flex-row gap-4">
<div className="flex-1 relative"> <div className="flex-1 relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
<input <input
type="text" type="text"
placeholder={translate('::App.DeveloperKit.Migration.SearchPlaceholder')} placeholder={translate('::App.DeveloperKit.Migration.SearchPlaceholder')}
@ -282,7 +282,7 @@ const MigrationManager: React.FC = () => {
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Filter className="w-5 h-5 text-slate-500" /> <FaFilter className="w-5 h-5 text-slate-500" />
<select <select
value={filterStatus} value={filterStatus}
onChange={(e) => onChange={(e) =>
@ -315,7 +315,7 @@ const MigrationManager: React.FC = () => {
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center gap-3 mb-2"> <div className="flex items-center gap-3 mb-2">
<div className="bg-blue-100 text-blue-600 p-2 rounded-lg"> <div className="bg-blue-100 text-blue-600 p-2 rounded-lg">
<Database className="w-5 h-5" /> <FaDatabase className="w-5 h-5" />
</div> </div>
<div> <div>
<h3 className="text-lg font-semibold text-slate-900"> <h3 className="text-lg font-semibold text-slate-900">
@ -332,14 +332,14 @@ const MigrationManager: React.FC = () => {
</div> </div>
<div className="flex items-center gap-4 text-xs text-slate-500"> <div className="flex items-center gap-4 text-xs text-slate-500">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Calendar className="w-3 h-3" /> <FaCalendarAlt className="w-3 h-3" />
<span> <span>
{translate('::App.DeveloperKit.Migration.Created')} {new Date(migration.creationTime).toLocaleDateString()} {translate('::App.DeveloperKit.Migration.Created')} {new Date(migration.creationTime).toLocaleDateString()}
</span> </span>
</div> </div>
{migration.appliedAt && ( {migration.appliedAt && (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<CheckCircle className="w-3 h-3" /> <FaCheckCircle className="w-3 h-3" />
<span> <span>
{translate('::App.DeveloperKit.Migration.AppliedLabel')} {new Date(migration.appliedAt).toLocaleDateString()} {translate('::App.DeveloperKit.Migration.AppliedLabel')} {new Date(migration.appliedAt).toLocaleDateString()}
</span> </span>
@ -364,7 +364,7 @@ const MigrationManager: React.FC = () => {
: 'text-orange-600 hover:text-orange-900 hover:bg-orange-50' : 'text-orange-600 hover:text-orange-900 hover:bg-orange-50'
}`} }`}
> >
<Eye className="w-4 h-4" /> <FaEye className="w-4 h-4" />
{translate('::App.DeveloperKit.Migration.ViewSQL')} {translate('::App.DeveloperKit.Migration.ViewSQL')}
{!migration.sqlScript && ( {!migration.sqlScript && (
<span className="ml-1 text-xs text-orange-500">({translate('::App.DeveloperKit.Migration.NoSQL')})</span> <span className="ml-1 text-xs text-orange-500">({translate('::App.DeveloperKit.Migration.NoSQL')})</span>
@ -379,7 +379,7 @@ const MigrationManager: React.FC = () => {
: 'text-slate-400 cursor-not-allowed' : 'text-slate-400 cursor-not-allowed'
}`} }`}
> >
<Download className="w-4 h-4" /> <FaDownload className="w-4 h-4" />
{translate('::App.DeveloperKit.Migration.Download')} {translate('::App.DeveloperKit.Migration.Download')}
</button> </button>
</div> </div>
@ -393,12 +393,12 @@ const MigrationManager: React.FC = () => {
> >
{applyingMigration === migration.id ? ( {applyingMigration === migration.id ? (
<> <>
<RefreshCw className="w-4 h-4 animate-spin" /> <FaSync className="w-4 h-4 animate-spin" />
{translate('::App.DeveloperKit.Migration.Applying')} {translate('::App.DeveloperKit.Migration.Applying')}
</> </>
) : ( ) : (
<> <>
<Play className="w-4 h-4" /> <FaPlay className="w-4 h-4" />
{translate('::App.DeveloperKit.Migration.ApplyMigration')} {translate('::App.DeveloperKit.Migration.ApplyMigration')}
</> </>
)} )}
@ -409,9 +409,9 @@ const MigrationManager: React.FC = () => {
className="flex items-center gap-2 bg-red-600 text-white px-3 py-2 rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" className="flex items-center gap-2 bg-red-600 text-white px-3 py-2 rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
> >
{deletingMigration === migration.id ? ( {deletingMigration === migration.id ? (
<RefreshCw className="w-4 h-4 animate-spin" /> <FaSync className="w-4 h-4 animate-spin" />
) : ( ) : (
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
)} )}
</button> </button>
</> </>
@ -424,12 +424,12 @@ const MigrationManager: React.FC = () => {
> >
{generatingEndpoints === migration.entityId ? ( {generatingEndpoints === migration.entityId ? (
<> <>
<RefreshCw className="w-4 h-4 animate-spin" /> <FaSync className="w-4 h-4 animate-spin" />
{translate('::App.DeveloperKit.Migration.Generating')} {translate('::App.DeveloperKit.Migration.Generating')}
</> </>
) : ( ) : (
<> <>
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
{translate('::App.DeveloperKit.Migration.GenerateCrudEndpoints')} {translate('::App.DeveloperKit.Migration.GenerateCrudEndpoints')}
</> </>
)} )}
@ -451,7 +451,7 @@ const MigrationManager: React.FC = () => {
) : ( ) : (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4"> <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<div className="flex items-center gap-2 text-yellow-800"> <div className="flex items-center gap-2 text-yellow-800">
<AlertCircle className="w-5 h-5" /> <FaRegBell className="w-5 h-5" />
<span className="font-medium">{translate('::App.DeveloperKit.Migration.NoSQLScript')}</span> <span className="font-medium">{translate('::App.DeveloperKit.Migration.NoSQLScript')}</span>
</div> </div>
<p className="text-yellow-700 text-sm mt-1"> <p className="text-yellow-700 text-sm mt-1">
@ -467,7 +467,7 @@ const MigrationManager: React.FC = () => {
<div className="mt-4 pt-4 border-t border-slate-200"> <div className="mt-4 pt-4 border-t border-slate-200">
<div className="bg-red-50 border border-red-200 rounded-lg p-4"> <div className="bg-red-50 border border-red-200 rounded-lg p-4">
<div className="flex items-center gap-2 text-red-800 mb-2"> <div className="flex items-center gap-2 text-red-800 mb-2">
<AlertCircle className="w-5 h-5" /> <FaRegBell className="w-5 h-5" />
<span className="font-medium">{translate('::App.DeveloperKit.Migration.MigrationFailed')}</span> <span className="font-medium">{translate('::App.DeveloperKit.Migration.MigrationFailed')}</span>
</div> </div>
<p className="text-red-700 text-sm">{migration.errorMessage}</p> <p className="text-red-700 text-sm">{migration.errorMessage}</p>
@ -483,7 +483,7 @@ const MigrationManager: React.FC = () => {
<div className="text-center py-12"> <div className="text-center py-12">
<div className="max-w-md mx-auto"> <div className="max-w-md mx-auto">
<div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4"> <div className="bg-slate-100 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4">
<Zap className="w-8 h-8 text-slate-500" /> <FaBolt className="w-8 h-8 text-slate-500" />
</div> </div>
<h3 className="text-lg font-medium text-slate-900 mb-2"> <h3 className="text-lg font-medium text-slate-900 mb-2">
{searchTerm || filterStatus !== 'all' ? translate('::App.DeveloperKit.Migration.NoMigrationsFound') : translate('::App.DeveloperKit.Migration.NoMigrationsYet')} {searchTerm || filterStatus !== 'all' ? translate('::App.DeveloperKit.Migration.NoMigrationsFound') : translate('::App.DeveloperKit.Migration.NoMigrationsYet')}

View file

@ -1,5 +1,10 @@
import React, { useCallback, useState } from 'react' import React, { useCallback, useState } from 'react'
import { Upload, File, X, AlertCircle } from 'lucide-react' import {
FaUpload,
FaFile,
FaTimes,
FaRegCircle
} from 'react-icons/fa';
interface FileUploadAreaProps { interface FileUploadAreaProps {
onFileUpload: (file: File) => void onFileUpload: (file: File) => void
@ -112,7 +117,7 @@ export const FileUploadArea: React.FC<FileUploadAreaProps> = ({
/> />
<div className="text-center"> <div className="text-center">
<Upload <FaUpload
className={`mx-auto h-3 w-3 ${dragActive ? 'text-blue-500' : 'text-slate-400'}`} className={`mx-auto h-3 w-3 ${dragActive ? 'text-blue-500' : 'text-slate-400'}`}
/> />
<div className="text-lg font-medium text-slate-700 mb-2"> <div className="text-lg font-medium text-slate-700 mb-2">
@ -128,7 +133,7 @@ export const FileUploadArea: React.FC<FileUploadAreaProps> = ({
<div className="border border-slate-200 rounded-lg p-4"> <div className="border border-slate-200 rounded-lg p-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center space-x-3 min-w-0 flex-1"> <div className="flex items-center space-x-3 min-w-0 flex-1">
<File className="w-8 h-8 text-blue-500 flex-shrink-0" /> <FaFile className="w-8 h-8 text-blue-500 flex-shrink-0" />
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="font-medium text-slate-800 truncate">{selectedFile.name}</div> <div className="font-medium text-slate-800 truncate">{selectedFile.name}</div>
<div className="text-sm text-slate-500">{formatFileSize(selectedFile.size)}</div> <div className="text-sm text-slate-500">{formatFileSize(selectedFile.size)}</div>
@ -138,7 +143,7 @@ export const FileUploadArea: React.FC<FileUploadAreaProps> = ({
onClick={clearFile} onClick={clearFile}
className="p-2 text-slate-400 hover:text-slate-600 hover:bg-slate-100 rounded-lg transition-colors" className="p-2 text-slate-400 hover:text-slate-600 hover:bg-slate-100 rounded-lg transition-colors"
> >
<X className="w-4 h-4" /> <FaTimes className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -146,7 +151,7 @@ export const FileUploadArea: React.FC<FileUploadAreaProps> = ({
{error && ( {error && (
<div className="flex items-center space-x-2 p-3 bg-red-50 border border-red-200 rounded-lg"> <div className="flex items-center space-x-2 p-3 bg-red-50 border border-red-200 rounded-lg">
<AlertCircle className="w-5 h-5 text-red-500" /> <FaRegCircle className="w-5 h-5 text-red-500" />
<span className="text-red-700">{error}</span> <span className="text-red-700">{error}</span>
</div> </div>
)} )}
@ -164,7 +169,7 @@ export const FileUploadArea: React.FC<FileUploadAreaProps> = ({
</> </>
) : ( ) : (
<> <>
<Upload className="w-4 h-4" /> <FaUpload className="w-4 h-4" />
<span>Upload File</span> <span>Upload File</span>
</> </>
)} )}

View file

@ -1,16 +1,16 @@
import React, { useState, useEffect, useMemo } from 'react' import React, { useState, useEffect, useMemo } from 'react'
import { import {
Upload, FaUpload,
CheckCircle, FaCheckCircle,
AlertCircle, FaRegBell,
Clock, FaClock,
RefreshCw, FaSync,
Eye, FaEye,
Trash2, FaTrashAlt,
Download, FaDownload,
FileSpreadsheet, FaFileExcel,
FileText, FaFileAlt
} from 'lucide-react' } from 'react-icons/fa';
import { FileUploadArea } from './FileUploadArea' import { FileUploadArea } from './FileUploadArea'
import { ImportPreview } from './ImportPreview' import { ImportPreview } from './ImportPreview'
import { ImportProgress } from './ImportProgress' import { ImportProgress } from './ImportProgress'
@ -168,14 +168,14 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
const getStatusIcon = (status: string) => { const getStatusIcon = (status: string) => {
switch (status) { switch (status) {
case 'uploaded': case 'uploaded':
return <CheckCircle className="w-5 h-5 text-green-500" /> return <FaCheckCircle className="w-5 h-5 text-green-500" />
case 'failed': case 'failed':
return <AlertCircle className="w-5 h-5 text-red-500" /> return <FaRegBell className="w-5 h-5 text-red-500" />
case 'processing': case 'processing':
case 'validating': case 'validating':
return <RefreshCw className="w-5 h-5 text-blue-500 animate-spin" /> return <FaSync className="w-5 h-5 text-blue-500 animate-spin" />
default: default:
return <Clock className="w-5 h-5 text-yellow-500" /> return <FaClock className="w-5 h-5 text-yellow-500" />
} }
} }
@ -233,9 +233,9 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
: 'text-slate-600 hover:text-slate-800 hover:bg-slate-50' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-50'
}`} }`}
> >
{tab === 'import' && <Upload className="w-4 h-4" />} {tab === 'import' && <FaUpload className="w-4 h-4" />}
{tab === 'preview' && <Eye className="w-4 h-4" />} {tab === 'preview' && <FaEye className="w-4 h-4" />}
{tab === 'history' && <Clock className="w-4 h-4" />} {tab === 'history' && <FaClock className="w-4 h-4" />}
<span className="capitalize">{tab}</span> <span className="capitalize">{tab}</span>
</button> </button>
))} ))}
@ -251,7 +251,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
<div className="bg-white rounded-xl shadow-sm border border-slate-200"> <div className="bg-white rounded-xl shadow-sm border border-slate-200">
<div className="px-3 py-3 border-b flex items-center justify-between"> <div className="px-3 py-3 border-b flex items-center justify-between">
<h3 className="text-xl font-semibold text-slate-800 flex items-center"> <h3 className="text-xl font-semibold text-slate-800 flex items-center">
<Download className="w-4 h-4 mr-2" /> <FaDownload className="w-4 h-4 mr-2" />
Template Columns ({editableColumns.length}) Template Columns ({editableColumns.length})
</h3> </h3>
@ -262,7 +262,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
disabled={generating} disabled={generating}
className="flex items-center gap-1.5 px-3 py-1.5 border border-green-200 rounded-md hover:border-green-300 hover:bg-green-50 transition-all duration-200 group disabled:opacity-50 disabled:cursor-not-allowed bg-white text-xs" className="flex items-center gap-1.5 px-3 py-1.5 border border-green-200 rounded-md hover:border-green-300 hover:bg-green-50 transition-all duration-200 group disabled:opacity-50 disabled:cursor-not-allowed bg-white text-xs"
> >
<FileSpreadsheet className="w-3.5 h-3.5 text-green-500 group-hover:scale-110 transition-transform" /> <FaFileExcel className="w-3.5 h-3.5 text-green-500 group-hover:scale-110 transition-transform" />
<span className="font-medium text-slate-700">Excel Template</span> <span className="font-medium text-slate-700">Excel Template</span>
</button> </button>
@ -271,7 +271,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
disabled={generating} disabled={generating}
className="flex items-center gap-1.5 px-3 py-1.5 border border-blue-200 rounded-md hover:border-blue-300 hover:bg-blue-50 transition-all duration-200 group disabled:opacity-50 disabled:cursor-not-allowed bg-white text-xs" className="flex items-center gap-1.5 px-3 py-1.5 border border-blue-200 rounded-md hover:border-blue-300 hover:bg-blue-50 transition-all duration-200 group disabled:opacity-50 disabled:cursor-not-allowed bg-white text-xs"
> >
<FileText className="w-3.5 h-3.5 text-blue-500 group-hover:scale-110 transition-transform" /> <FaFileAlt className="w-3.5 h-3.5 text-blue-500 group-hover:scale-110 transition-transform" />
<span className="font-medium text-slate-700">CSV Template</span> <span className="font-medium text-slate-700">CSV Template</span>
</button> </button>
</div> </div>
@ -349,7 +349,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
<div className="lg:col-span-1"> <div className="lg:col-span-1">
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-4 h-full"> <div className="bg-white rounded-xl shadow-sm border border-slate-200 p-4 h-full">
<h2 className="text-xl font-semibold text-slate-800 mb-4 flex items-center"> <h2 className="text-xl font-semibold text-slate-800 mb-4 flex items-center">
<Upload className="w-5 h-5 mr-2 text-green-500" /> <FaUpload className="w-5 h-5 mr-2 text-green-500" />
Upload Data Upload Data
</h2> </h2>
<FileUploadArea <FileUploadArea
@ -387,7 +387,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
) : ( ) : (
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-12"> <div className="bg-white rounded-xl shadow-sm border border-slate-200 p-12">
<div className="text-center text-slate-500"> <div className="text-center text-slate-500">
<Eye className="w-16 h-16 mx-auto mb-4 text-slate-300" /> <FaEye className="w-16 h-16 mx-auto mb-4 text-slate-300" />
<div className="text-xl font-medium mb-2">No Data to Preview</div> <div className="text-xl font-medium mb-2">No Data to Preview</div>
<div>Upload a file to see the preview here</div> <div>Upload a file to see the preview here</div>
</div> </div>
@ -400,7 +400,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
<div className="bg-white rounded-xl shadow-sm border border-slate-200"> <div className="bg-white rounded-xl shadow-sm border border-slate-200">
<div className="p-3 border-b border-slate-200"> <div className="p-3 border-b border-slate-200">
<h2 className="text-xl font-semibold text-slate-800 flex items-center"> <h2 className="text-xl font-semibold text-slate-800 flex items-center">
<Clock className="w-5 h-5 mr-2 text-indigo-500" /> <FaClock className="w-5 h-5 mr-2 text-indigo-500" />
Import History Import History
</h2> </h2>
</div> </div>
@ -458,7 +458,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
}`} }`}
title="View execution details" title="View execution details"
> >
<Eye className="w-4 h-4" /> <FaEye className="w-4 h-4" />
</button> </button>
<button <button
onClick={async () => { onClick={async () => {
@ -487,7 +487,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
className="p-2 rounded-lg transition-colors text-slate-400 hover:text-blue-500 hover:bg-blue-50" className="p-2 rounded-lg transition-colors text-slate-400 hover:text-blue-500 hover:bg-blue-50"
title="Refresh execution details" title="Refresh execution details"
> >
<RefreshCw className="w-4 h-4" /> <FaSync className="w-4 h-4" />
</button> </button>
<button <button
onClick={async () => { onClick={async () => {
@ -509,7 +509,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
: 'Delete this import session' : 'Delete this import session'
} }
> >
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -521,7 +521,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
<div className="p-3"> <div className="p-3">
{loadingExecutes.has(session.id) ? ( {loadingExecutes.has(session.id) ? (
<div className="flex items-center space-x-2 text-slate-500 py-2"> <div className="flex items-center space-x-2 text-slate-500 py-2">
<RefreshCw className="w-4 h-4 animate-spin" /> <FaSync className="w-4 h-4 animate-spin" />
<span className="text-sm">Loading execution details...</span> <span className="text-sm">Loading execution details...</span>
</div> </div>
) : sessionExecutes[session.id] && sessionExecutes[session.id].length > 0 ? ( ) : sessionExecutes[session.id] && sessionExecutes[session.id].length > 0 ? (
@ -561,16 +561,16 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
{/* Sağ: Status */} {/* Sağ: Status */}
<div className="flex items-center space-x-2 flex-shrink-0"> <div className="flex items-center space-x-2 flex-shrink-0">
{execute.status === 'completed' && ( {execute.status === 'completed' && (
<CheckCircle className="w-4 h-4 text-green-500" /> <FaCheckCircle className="w-4 h-4 text-green-500" />
)} )}
{execute.status === 'processing' && ( {execute.status === 'processing' && (
<RefreshCw className="w-4 h-4 text-blue-500 animate-spin" /> <FaSync className="w-4 h-4 text-blue-500 animate-spin" />
)} )}
{execute.status === 'validating' && ( {execute.status === 'validating' && (
<Clock className="w-4 h-4 text-yellow-500" /> <FaClock className="w-4 h-4 text-yellow-500" />
)} )}
{execute.status === 'failed' && ( {execute.status === 'failed' && (
<AlertCircle className="w-4 h-4 text-red-500" /> <FaRegBell className="w-4 h-4 text-red-500" />
)} )}
<div <div
className={`text-xs font-medium ${ className={`text-xs font-medium ${
@ -605,7 +605,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
{importHistory.length === 0 && ( {importHistory.length === 0 && (
<div className="p-12 text-center text-slate-500"> <div className="p-12 text-center text-slate-500">
<Clock className="w-12 h-12 mx-auto mb-4 text-slate-300" /> <FaClock className="w-12 h-12 mx-auto mb-4 text-slate-300" />
<div className="text-lg font-medium mb-2">No import history</div> <div className="text-lg font-medium mb-2">No import history</div>
<div>Your import history will appear here</div> <div>Your import history will appear here</div>
</div> </div>

View file

@ -1,5 +1,11 @@
import React, { useState, useEffect, useRef } from 'react' import React, { useState, useEffect, useRef } from 'react'
import { CheckCircle, AlertTriangle, Eye, Play, X } from 'lucide-react' import {
FaCheckCircle,
FaExclamationTriangle,
FaEye,
FaPlay,
FaTimes
} from 'react-icons/fa';
import { ListFormImportDto } from '@/proxy/imports/models' import { ListFormImportDto } from '@/proxy/imports/models'
import { GridDto } from '@/proxy/form/models' import { GridDto } from '@/proxy/form/models'
import { ImportService } from '@/services/import.service' import { ImportService } from '@/services/import.service'
@ -149,7 +155,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-center gap-4"> <div className="flex flex-col lg:flex-row lg:items-center lg:justify-center gap-4">
{/* Başlık kısmı - Üstte mobile, solda desktop */} {/* Başlık kısmı - Üstte mobile, solda desktop */}
<div className="flex items-center order-1 lg:order-none"> <div className="flex items-center order-1 lg:order-none">
<Eye className="w-5 h-5 mr-2 text-blue-500" /> <FaEye className="w-5 h-5 mr-2 text-blue-500" />
<h3 className="text-xl font-semibold text-slate-800">Import Preview</h3> <h3 className="text-xl font-semibold text-slate-800">Import Preview</h3>
</div> </div>
@ -236,7 +242,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
) : previewData && previewData.headers && previewData.headers.length === 0 ? ( ) : previewData && previewData.headers && previewData.headers.length === 0 ? (
<div className="p-6 border-b border-slate-200"> <div className="p-6 border-b border-slate-200">
<div className="text-center py-8"> <div className="text-center py-8">
<AlertTriangle className="w-12 h-12 mx-auto mb-4 text-yellow-500" /> <FaExclamationTriangle className="w-12 h-12 mx-auto mb-4 text-yellow-500" />
<h4 className="font-semibold text-slate-800 mb-2">No Data Found</h4> <h4 className="font-semibold text-slate-800 mb-2">No Data Found</h4>
<p className="text-slate-600"> <p className="text-slate-600">
Unable to parse data from the uploaded file. Please check the file format and content. Unable to parse data from the uploaded file. Please check the file format and content.
@ -259,7 +265,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
{showSuccessMessage && lastExecutionResult && ( {showSuccessMessage && lastExecutionResult && (
<div className="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg"> <div className="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg">
<div className="flex items-center space-x-2 text-green-700"> <div className="flex items-center space-x-2 text-green-700">
<CheckCircle className="w-5 h-5" /> <FaCheckCircle className="w-5 h-5" />
<span className="font-medium"> <span className="font-medium">
Import completed successfully! {lastExecutionResult.successCount} of{' '} Import completed successfully! {lastExecutionResult.successCount} of{' '}
{lastExecutionResult.selectedCount} rows were imported. {lastExecutionResult.selectedCount} rows were imported.
@ -272,21 +278,21 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
{selectedRows.length === 0 && (previewData?.rows?.length || 0) > 0 && ( {selectedRows.length === 0 && (previewData?.rows?.length || 0) > 0 && (
<div className="flex items-center space-x-2 text-orange-600"> <div className="flex items-center space-x-2 text-orange-600">
<AlertTriangle className="w-5 h-5" /> <FaExclamationTriangle className="w-5 h-5" />
<span className="font-medium">Please select rows to import using checkboxes</span> <span className="font-medium">Please select rows to import using checkboxes</span>
</div> </div>
)} )}
{selectedRows.length > 0 && ( {selectedRows.length > 0 && (
<div className="flex items-center space-x-2 text-blue-600"> <div className="flex items-center space-x-2 text-blue-600">
<CheckCircle className="w-5 h-5" /> <FaCheckCircle className="w-5 h-5" />
<span className="font-medium">{selectedRows.length} rows selected for import</span> <span className="font-medium">{selectedRows.length} rows selected for import</span>
</div> </div>
)} )}
{(previewData?.rows?.length || 0) === 0 && ( {(previewData?.rows?.length || 0) === 0 && (
<div className="flex items-center space-x-2 text-red-600"> <div className="flex items-center space-x-2 text-red-600">
<AlertTriangle className="w-5 h-5" /> <FaExclamationTriangle className="w-5 h-5" />
<span className="font-medium">No data available for import</span> <span className="font-medium">No data available for import</span>
</div> </div>
)} )}
@ -294,7 +300,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
<div className="flex space-x-3"> <div className="flex space-x-3">
<button className="px-4 py-2 text-slate-600 hover:text-slate-800 hover:bg-slate-100 rounded-lg transition-colors flex items-center space-x-2"> <button className="px-4 py-2 text-slate-600 hover:text-slate-800 hover:bg-slate-100 rounded-lg transition-colors flex items-center space-x-2">
<X className="w-4 h-4" /> <FaTimes className="w-4 h-4" />
<span>Cancel</span> <span>Cancel</span>
</button> </button>
@ -310,7 +316,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
</> </>
) : ( ) : (
<> <>
<Play className="w-4 h-4" /> <FaPlay className="w-4 h-4" />
<span>Execute Import</span> <span>Execute Import</span>
</> </>
)} )}

View file

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { RefreshCw, Upload, CheckCircle } from 'lucide-react' import { FaSync, FaUpload, FaCheckCircle } from 'react-icons/fa';
import { ListFormImportDto } from '@/proxy/imports/models' import { ListFormImportDto } from '@/proxy/imports/models'
interface ImportProgressProps { interface ImportProgressProps {
@ -44,14 +44,14 @@ export const ImportProgress: React.FC<ImportProgressProps> = ({ session }) => {
const getStatusIcon = () => { const getStatusIcon = () => {
switch (session.status) { switch (session.status) {
case 'uploading': case 'uploading':
return <Upload className="w-6 h-6 text-blue-500" /> return <FaUpload className="w-6 h-6 text-blue-500" />
case 'validating': case 'validating':
case 'processing': case 'processing':
return <RefreshCw className="w-6 h-6 text-blue-500 animate-spin" /> return <FaSync className="w-6 h-6 text-blue-500 animate-spin" />
case 'uploaded': case 'uploaded':
return <CheckCircle className="w-6 h-6 text-green-500" /> return <FaCheckCircle className="w-6 h-6 text-green-500" />
default: default:
return <RefreshCw className="w-6 h-6 text-blue-500 animate-spin" /> return <FaSync className="w-6 h-6 text-blue-500 animate-spin" />
} }
} }

View file

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { LayoutDashboard, Database, Zap, Server, Puzzle } from 'lucide-react' import { FaTachometerAlt, FaDatabase, FaBolt, FaServer, FaPuzzlePiece } from 'react-icons/fa';
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
@ -18,31 +18,31 @@ const DeveloperLayout: React.FC<DeveloperLayoutProps> = ({ children }) => {
{ {
id: 'dashboard', id: 'dashboard',
label: translate('::App.DeveloperKit.Dashboard'), label: translate('::App.DeveloperKit.Dashboard'),
icon: LayoutDashboard, icon: FaTachometerAlt,
path: ROUTES_ENUM.protected.saas.developerKit, path: ROUTES_ENUM.protected.saas.developerKit,
}, },
{ {
id: 'entities', id: 'entities',
label: translate('::App.DeveloperKit.Entity'), label: translate('::App.DeveloperKit.Entity'),
icon: Database, icon: FaDatabase,
path: ROUTES_ENUM.protected.saas.developerKitEntities, path: ROUTES_ENUM.protected.saas.developerKitEntities,
}, },
{ {
id: 'migrations', id: 'migrations',
label: translate('::App.DeveloperKit.Migrations'), label: translate('::App.DeveloperKit.Migrations'),
icon: Zap, icon: FaBolt,
path: ROUTES_ENUM.protected.saas.developerKitMigrations, path: ROUTES_ENUM.protected.saas.developerKitMigrations,
}, },
{ {
id: 'endpoints', id: 'endpoints',
label: translate('::App.DeveloperKit.Endpoints'), label: translate('::App.DeveloperKit.Endpoints'),
icon: Server, icon: FaServer,
path: ROUTES_ENUM.protected.saas.developerKitEndpoints, path: ROUTES_ENUM.protected.saas.developerKitEndpoints,
}, },
{ {
id: 'components', id: 'components',
label: translate('::App.DeveloperKit.Components'), label: translate('::App.DeveloperKit.Components'),
icon: Puzzle, icon: FaPuzzlePiece,
path: ROUTES_ENUM.protected.saas.developerKitComponents, path: ROUTES_ENUM.protected.saas.developerKitComponents,
}, },
] ]

View file

@ -1,23 +1,24 @@
import View from '@/views/Views' import View from '@/views/Views'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { useLocation, Link } from 'react-router-dom' import { useLocation, Link } from 'react-router-dom'
import { import {
Menu, FaBars,
X, FaTimes,
Home, FaHome,
Info, FaInfoCircle,
Package, FaVectorSquare,
Briefcase, FaBriefcase,
BookOpen, FaBook,
Phone, FaPhone,
Facebook, FaFacebook,
Twitter, FaTwitter,
Linkedin, FaLinkedin,
Instagram, FaInstagram,
MapPin, FaMapPin,
Mail, FaEnvelope,
PlayCircle, FaPlayCircle,
} from 'lucide-react' FaBookOpen
} from 'react-icons/fa';
import Logo from '@/views/public/Logo' import Logo from '@/views/public/Logo'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -65,43 +66,43 @@ const PublicLayout = () => {
resourceKey: 'Public.nav.home', resourceKey: 'Public.nav.home',
name: translate('::Public.nav.home'), name: translate('::Public.nav.home'),
path: ROUTES_ENUM.public.home, path: ROUTES_ENUM.public.home,
icon: Home, icon: FaHome,
}, },
{ {
resourceKey: 'Public.nav.about', resourceKey: 'Public.nav.about',
name: translate('::Public.nav.about'), name: translate('::Public.nav.about'),
path: ROUTES_ENUM.public.about, path: ROUTES_ENUM.public.about,
icon: Info, icon: FaInfoCircle,
}, },
{ {
resourceKey: 'Public.nav.services', resourceKey: 'Public.nav.services',
name: translate('::Public.nav.services'), name: translate('::Public.nav.services'),
path: ROUTES_ENUM.public.services, path: ROUTES_ENUM.public.services,
icon: Briefcase, icon: FaBriefcase,
}, },
{ {
resourceKey: 'Public.nav.products', resourceKey: 'Public.nav.products',
name: translate('::Public.nav.products'), name: translate('::Public.nav.products'),
path: ROUTES_ENUM.public.products, path: ROUTES_ENUM.public.products,
icon: Package, icon: FaVectorSquare,
}, },
{ {
resourceKey: 'Public.nav.blog', resourceKey: 'Public.nav.blog',
name: translate('::Public.nav.blog'), name: translate('::Public.nav.blog'),
path: ROUTES_ENUM.public.blog, path: ROUTES_ENUM.public.blog,
icon: BookOpen, icon: FaBookOpen,
}, },
{ {
resourceKey: 'Public.nav.demo', resourceKey: 'Public.nav.demo',
name: translate('::Public.nav.demo'), name: translate('::Public.nav.demo'),
action: () => setIsDemoOpen(true), action: () => setIsDemoOpen(true),
icon: PlayCircle, icon: FaPlayCircle,
}, },
{ {
resourceKey: 'Public.nav.contact', resourceKey: 'Public.nav.contact',
name: translate('::Public.nav.contact'), name: translate('::Public.nav.contact'),
path: ROUTES_ENUM.public.contact, path: ROUTES_ENUM.public.contact,
icon: Phone, icon: FaPhone,
}, },
{ {
resourceKey: 'Public.nav.giris', resourceKey: 'Public.nav.giris',
@ -162,7 +163,7 @@ const PublicLayout = () => {
{/* Mobile Menu Button */} {/* Mobile Menu Button */}
<button className="md:hidden text-white" onClick={toggleMenu} aria-label="Toggle menu"> <button className="md:hidden text-white" onClick={toggleMenu} aria-label="Toggle menu">
{isOpen ? <X size={24} /> : <Menu size={24} />} {isOpen ? <FaTimes size={24} /> : <FaBars size={24} />}
</button> </button>
</div> </div>
@ -222,7 +223,7 @@ const PublicLayout = () => {
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors" className="text-gray-400 hover:text-white transition-colors"
> >
<Facebook size={20} /> <FaFacebook size={20} />
</a> </a>
<a <a
href="https://twitter.com/sozsoft" href="https://twitter.com/sozsoft"
@ -230,7 +231,7 @@ const PublicLayout = () => {
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors" className="text-gray-400 hover:text-white transition-colors"
> >
<Twitter size={20} /> <FaTwitter size={20} />
</a> </a>
<a <a
href="https://linkedin.com/sozsoft" href="https://linkedin.com/sozsoft"
@ -238,7 +239,7 @@ const PublicLayout = () => {
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors" className="text-gray-400 hover:text-white transition-colors"
> >
<Linkedin size={20} /> <FaLinkedin size={20} />
</a> </a>
<a <a
href="https://instagram.com/sozsoft" href="https://instagram.com/sozsoft"
@ -246,7 +247,7 @@ const PublicLayout = () => {
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors" className="text-gray-400 hover:text-white transition-colors"
> >
<Instagram size={20} /> <FaInstagram size={20} />
</a> </a>
</div> </div>
</div> </div>
@ -372,11 +373,11 @@ const PublicLayout = () => {
</h3> </h3>
<ul className="space-y-3"> <ul className="space-y-3">
<li className="flex items-start space-x-3"> <li className="flex items-start space-x-3">
<MapPin size={20} className="text-gray-400 mt-1 flex-shrink-0" /> <FaMapPin size={20} className="text-gray-400 mt-1 flex-shrink-0" />
<span className="text-gray-400">{translate('::Public.footer.address')}</span> <span className="text-gray-400">{translate('::Public.footer.address')}</span>
</li> </li>
<li className="flex items-center space-x-3"> <li className="flex items-center space-x-3">
<Phone size={20} className="text-gray-400 flex-shrink-0" /> <FaPhone size={20} className="text-gray-400 flex-shrink-0" />
<a <a
href="tel:+905447697638" href="tel:+905447697638"
className="text-gray-400 hover:text-white transition-colors" className="text-gray-400 hover:text-white transition-colors"
@ -385,7 +386,7 @@ const PublicLayout = () => {
</a> </a>
</li> </li>
<li className="flex items-center space-x-3"> <li className="flex items-center space-x-3">
<Mail size={20} className="text-gray-400 flex-shrink-0" /> <FaEnvelope size={20} className="text-gray-400 flex-shrink-0" />
<a <a
href="mailto:destek@sozsoft.com" href="mailto:destek@sozsoft.com"
className="text-gray-400 hover:text-white transition-colors" className="text-gray-400 hover:text-white transition-colors"

View file

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { Calendar, Clock, Minus, Plus, ShoppingCart } from 'lucide-react' import { FaCalendar, FaClock, FaMinus, FaPlus, FaShoppingCart } from 'react-icons/fa';
import { BillingCycle } from '@/proxy/order/models' import { BillingCycle } from '@/proxy/order/models'
import { CartState } from '@/utils/cartUtils' import { CartState } from '@/utils/cartUtils'
import { useScroll } from '@/contexts/ScrollContext' import { useScroll } from '@/contexts/ScrollContext'
@ -41,7 +41,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
<div className="flex flex-col sm:flex-row items-center justify-between gap-4"> <div className="flex flex-col sm:flex-row items-center justify-between gap-4">
<div className="flex items-center space-x-6"> <div className="flex items-center space-x-6">
<div className="flex items-center space-x-2 rounded-lg"> <div className="flex items-center space-x-2 rounded-lg">
<Calendar className="w-5 h-5 text-gray-600" /> <FaCalendar className="w-5 h-5 text-gray-600" />
<span className="font-medium text-gray-900">Faturalama Döngüsü:</span> <span className="font-medium text-gray-900">Faturalama Döngüsü:</span>
</div> </div>
@ -84,7 +84,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
<div className="flex items-center space-x-6"> <div className="flex items-center space-x-6">
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Clock className="w-5 h-5 text-gray-600" /> <FaClock className="w-5 h-5 text-gray-600" />
<span className="font-medium text-gray-900">Periyod:</span> <span className="font-medium text-gray-900">Periyod:</span>
</div> </div>
@ -99,7 +99,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
disabled={globalPeriod <= 1 || hasCartItems} disabled={globalPeriod <= 1 || hasCartItems}
title={hasCartItems ? 'Sepette ürün varken periyod değiştirilemez' : undefined} title={hasCartItems ? 'Sepette ürün varken periyod değiştirilemez' : undefined}
> >
<Minus className="w-4 h-4" /> <FaMinus className="w-4 h-4" />
</button> </button>
<div className="flex items-center space-x-2 bg-gray-50 px-4 py-2 rounded-lg"> <div className="flex items-center space-x-2 bg-gray-50 px-4 py-2 rounded-lg">
@ -119,7 +119,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
disabled={hasCartItems} disabled={hasCartItems}
title={hasCartItems ? 'Sepette ürün varken periyod değiştirilemez' : undefined} title={hasCartItems ? 'Sepette ürün varken periyod değiştirilemez' : undefined}
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -128,7 +128,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
onClick={onCartClick} onClick={onCartClick}
className="relative flex items-center gap-2 p-2 bg-green-600 text-white hover:bg-green-700 transition-colors rounded-lg shadow-md" className="relative flex items-center gap-2 p-2 bg-green-600 text-white hover:bg-green-700 transition-colors rounded-lg shadow-md"
> >
<ShoppingCart className="w-5 h-5" /> <FaShoppingCart className="w-5 h-5" />
<span className="font-medium text-sm">{translate('::Public.nav.basket')}</span> <span className="font-medium text-sm">{translate('::Public.nav.basket')}</span>
{cartItemsCount > 0 && ( {cartItemsCount > 0 && (

View file

@ -1,5 +1,11 @@
import React from 'react'; import React from 'react';
import { X, Minus, Plus, ShoppingBag, Trash2 } from 'lucide-react'; import {
FaTimes,
FaMinus,
FaPlus,
FaShoppingBag,
FaTrash
} from 'react-icons/fa';
import { BillingCycle, BasketItem } from '@/proxy/order/models'; import { BillingCycle, BasketItem } from '@/proxy/order/models';
interface CartState { interface CartState {
@ -60,14 +66,14 @@ export const Cart: React.FC<CartProps> = ({
className="p-2 text-red-500 hover:bg-red-50 rounded-lg transition-colors" className="p-2 text-red-500 hover:bg-red-50 rounded-lg transition-colors"
title="Sepeti Temizle" title="Sepeti Temizle"
> >
<Trash2 className="w-5 h-5" /> <FaTrash className="w-5 h-5" />
</button> </button>
)} )}
<button <button
onClick={onClose} onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors" className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
> >
<X className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
</div> </div>
@ -75,7 +81,7 @@ export const Cart: React.FC<CartProps> = ({
<div className="flex-1 overflow-y-auto p-6"> <div className="flex-1 overflow-y-auto p-6">
{cartState.items.length === 0 ? ( {cartState.items.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-gray-500"> <div className="flex flex-col items-center justify-center h-full text-gray-500">
<ShoppingBag className="w-16 h-16 mb-4" /> <FaShoppingBag className="w-16 h-16 mb-4" />
<p className="text-lg font-medium">Sepetiniz boş</p> <p className="text-lg font-medium">Sepetiniz boş</p>
<p className="text-sm">Ürün eklemek için katalogdan seçim yapın</p> <p className="text-sm">Ürün eklemek için katalogdan seçim yapın</p>
</div> </div>
@ -91,7 +97,7 @@ export const Cart: React.FC<CartProps> = ({
onClick={() => removeItem(item.product.id)} onClick={() => removeItem(item.product.id)}
className="text-red-500 hover:text-red-700 ml-2" className="text-red-500 hover:text-red-700 ml-2"
> >
<X className="w-4 h-4" /> <FaTimes className="w-4 h-4" />
</button> </button>
</div> </div>
@ -115,14 +121,14 @@ export const Cart: React.FC<CartProps> = ({
onClick={() => updateQuantity(item.product.id, item.quantity - 1)} onClick={() => updateQuantity(item.product.id, item.quantity - 1)}
className="p-1 rounded border border-gray-300 hover:bg-gray-50" className="p-1 rounded border border-gray-300 hover:bg-gray-50"
> >
<Minus className="w-3 h-3" /> <FaMinus className="w-3 h-3" />
</button> </button>
<span className="w-8 text-center text-sm">{item.quantity}</span> <span className="w-8 text-center text-sm">{item.quantity}</span>
<button <button
onClick={() => updateQuantity(item.product.id, item.quantity + 1)} onClick={() => updateQuantity(item.product.id, item.quantity + 1)}
className="p-1 rounded border border-gray-300 hover:bg-gray-50" className="p-1 rounded border border-gray-300 hover:bg-gray-50"
> >
<Plus className="w-3 h-3" /> <FaPlus className="w-3 h-3" />
</button> </button>
</div> </div>
)} )}

View file

@ -1,5 +1,8 @@
import React from 'react' import React from 'react'
import { CheckCircle, Download, ArrowLeft } from 'lucide-react' import {
FaCheckCircle,
FaArrowLeft
} from 'react-icons/fa';
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
@ -15,7 +18,7 @@ export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId, onBackToSho
<div className="max-w-2xl mx-auto text-center"> <div className="max-w-2xl mx-auto text-center">
<div className="bg-white rounded-xl shadow-lg border border-gray-200 p-8"> <div className="bg-white rounded-xl shadow-lg border border-gray-200 p-8">
<div className="mb-6"> <div className="mb-6">
<CheckCircle className="w-16 h-16 text-green-500 mx-auto mb-4" /> <FaCheckCircle className="w-16 h-16 text-green-500 mx-auto mb-4" />
<h2 className="text-2xl font-bold text-gray-900 mb-2">Siparişiniz Başarıyla Alındı!</h2> <h2 className="text-2xl font-bold text-gray-900 mb-2">Siparişiniz Başarıyla Alındı!</h2>
<p className="text-gray-600"> <p className="text-gray-600">
Sipariş numaranız: <span className="font-semibold text-blue-600">#{orderId}</span> Sipariş numaranız: <span className="font-semibold text-blue-600">#{orderId}</span>
@ -36,7 +39,7 @@ export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId, onBackToSho
onClick={() => navigate(ROUTES_ENUM.public.home)} onClick={() => navigate(ROUTES_ENUM.public.home)}
className="flex items-center justify-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors" className="flex items-center justify-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
> >
<ArrowLeft className="w-4 h-4 mr-2" /> <FaArrowLeft className="w-4 h-4 mr-2" />
Ana Sayfa'ya Dön Ana Sayfa'ya Dön
</button> </button>
</div> </div>

View file

@ -1,19 +1,19 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { import {
CreditCard, FaCreditCard,
Lock, FaLock,
ArrowLeft, FaArrowLeft,
User, FaUser,
Building, FaBuilding,
Mail, FaMailBulk,
Phone, FaPhone,
MapPin, FaMapMarkerAlt,
Map, FaMap,
Globe, FaGlobe,
Banknote, FaMoneyBillWave,
BadgeDollarSign, FaDollarSign,
UserPlus, FaUserPlus
} from 'lucide-react' } from 'react-icons/fa';
import { import {
BillingCycle, BillingCycle,
BasketItem, BasketItem,
@ -125,42 +125,42 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
{tenant && ( {tenant && (
<> <>
<h2 className="text-lg font-semibold mb-4 flex items-center"> <h2 className="text-lg font-semibold mb-4 flex items-center">
<User className="w-5 h-5 text-green-600 mr-2" /> Müşteri Bilgileri <FaUser className="w-5 h-5 text-green-600 mr-2" /> Müşteri Bilgileri
</h2> </h2>
<div className="pt-4 border-t border-gray-200"> <div className="pt-4 border-t border-gray-200">
<div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700"> <div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<User className="w-4 h-4 text-gray-500" /> <FaUser className="w-4 h-4 text-gray-500" />
<span className="font-medium">Kurum Kodu:</span> <span className="font-medium">Kurum Kodu:</span>
<span>{tenant.name}</span> <span>{tenant.name}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<User className="w-4 h-4 text-gray-500" /> <FaUser className="w-4 h-4 text-gray-500" />
<span className="font-medium">Kurucu:</span> <span className="font-medium">Kurucu:</span>
<span>{tenant.founder}</span> <span>{tenant.founder}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Building className="w-4 h-4 text-gray-500" /> <FaBuilding className="w-4 h-4 text-gray-500" />
<span className="font-medium">Şirket:</span> <span className="font-medium">Şirket:</span>
<span>{tenant.institutionName}</span> <span>{tenant.institutionName}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Mail className="w-4 h-4 text-gray-500" /> <FaMailBulk className="w-4 h-4 text-gray-500" />
<span className="font-medium">E-posta:</span> <span className="font-medium">E-posta:</span>
<span>{tenant.email}</span> <span>{tenant.email}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Phone className="w-4 h-4 text-gray-500" /> <FaPhone className="w-4 h-4 text-gray-500" />
<span className="font-medium">Telefon:</span> <span className="font-medium">Telefon:</span>
<span>{tenant.phone}</span> <span>{tenant.phone}</span>
</div> </div>
<div className="flex items-start gap-2"> <div className="flex items-start gap-2">
<MapPin className="w-4 h-4 text-gray-500 mt-0.5" /> <FaMapMarkerAlt className="w-4 h-4 text-gray-500 mt-0.5" />
<div> <div>
<span className="font-medium">Adres:</span> <span className="font-medium">Adres:</span>
<div>{tenant.address}</div> <div>{tenant.address}</div>
@ -168,44 +168,44 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Globe className="w-4 h-4 text-gray-500" /> <FaGlobe className="w-4 h-4 text-gray-500" />
<span className="font-medium">Ülke:</span> <span className="font-medium">Ülke:</span>
<span>{tenant.country}</span> <span>{tenant.country}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Globe className="w-4 h-4 text-gray-500" /> <FaGlobe className="w-4 h-4 text-gray-500" />
<span className="font-medium">Şehir:</span> <span className="font-medium">Şehir:</span>
<span>{tenant.city}</span> <span>{tenant.city}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Map className="w-4 h-4 text-gray-500" /> <FaMap className="w-4 h-4 text-gray-500" />
<span className="font-medium">İlçe:</span> <span className="font-medium">İlçe:</span>
<span>{tenant.district}</span> <span>{tenant.district}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<MapPin className="w-4 h-4 text-gray-500" /> <FaMapMarkerAlt className="w-4 h-4 text-gray-500" />
<span className="font-medium">Posta Kodu:</span> <span className="font-medium">Posta Kodu:</span>
<span>{tenant.postalCode}</span> <span>{tenant.postalCode}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Banknote className="w-4 h-4 text-gray-500" /> <FaMoneyBillWave className="w-4 h-4 text-gray-500" />
<span className="font-medium">Vergi Dairesi:</span> <span className="font-medium">Vergi Dairesi:</span>
<span>{tenant.taxOffice}</span> <span>{tenant.taxOffice}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<BadgeDollarSign className="w-4 h-4 text-gray-500" /> <FaDollarSign className="w-4 h-4 text-gray-500" />
<span className="font-medium">Vergi No:</span> <span className="font-medium">Vergi No:</span>
<span>{tenant.vknTckn}</span> <span>{tenant.vknTckn}</span>
</div> </div>
{tenant.reference && ( {tenant.reference && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<UserPlus className="w-4 h-4 text-gray-500" /> <FaUserPlus className="w-4 h-4 text-gray-500" />
<span className="font-medium">Referans:</span> <span className="font-medium">Referans:</span>
<span>{tenant.reference}</span> <span>{tenant.reference}</span>
</div> </div>
@ -221,7 +221,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
{/* 1. Sütun: Ödeme Yöntemi */} {/* 1. Sütun: Ödeme Yöntemi */}
<div className="bg-white rounded-xl shadow border p-6"> <div className="bg-white rounded-xl shadow border p-6">
<h2 className="text-lg font-semibold mb-4 flex items-center"> <h2 className="text-lg font-semibold mb-4 flex items-center">
<Lock className="w-5 h-5 text-green-600 mr-2" /> Ödeme Yöntemi <FaLock className="w-5 h-5 text-green-600 mr-2" /> Ödeme Yöntemi
</h2> </h2>
<div className="space-y-2"> <div className="space-y-2">
{paymentMethods.map((method) => ( {paymentMethods.map((method) => (
@ -401,14 +401,14 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
onClick={onBack} onClick={onBack}
className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg" className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg"
> >
<ArrowLeft className="w-4 h-4 mr-2" /> <FaArrowLeft className="w-4 h-4 mr-2" />
Geri Geri
</button> </button>
<button <button
type="submit" type="submit"
className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg" className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg"
> >
<CreditCard className="w-5 h-5 mr-2" /> <FaCreditCard className="w-5 h-5 mr-2" />
{selectedPaymentMethod === 'bank-transfer' ? 'Siparişi Tamamla' : 'Ödeme Yap'} {selectedPaymentMethod === 'bank-transfer' ? 'Siparişi Tamamla' : 'Ödeme Yap'}
</button> </button>
</div> </div>

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Plus, Minus } from 'lucide-react'; import { FaPlus, FaMinus } from 'react-icons/fa';
import { BillingCycle, Product, ProductDto } from '@/proxy/order/models'; import { BillingCycle, Product, ProductDto } from '@/proxy/order/models';
import { CartState } from '@/utils/cartUtils'; import { CartState } from '@/utils/cartUtils';
@ -115,14 +115,14 @@ export const ProductCard: React.FC<ProductCardProps> = ({
onClick={() => setQuantity(Math.max(1, quantity - 1))} onClick={() => setQuantity(Math.max(1, quantity - 1))}
className="p-1 rounded-md border border-gray-300 hover:bg-gray-50 transition-colors" className="p-1 rounded-md border border-gray-300 hover:bg-gray-50 transition-colors"
> >
<Minus className="w-4 h-4" /> <FaMinus className="w-4 h-4" />
</button> </button>
<span className="w-12 text-center font-medium">{quantity}</span> <span className="w-12 text-center font-medium">{quantity}</span>
<button <button
onClick={() => setQuantity(quantity + 1)} onClick={() => setQuantity(quantity + 1)}
className="p-1 rounded-md border border-gray-300 hover:bg-gray-50 transition-colors" className="p-1 rounded-md border border-gray-300 hover:bg-gray-50 transition-colors"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
import React, { useState, useMemo, useEffect } from 'react' import React, { useState, useMemo, useEffect } from 'react'
import { Filter, Search } from 'lucide-react' import { FaFilter, FaSearch } from 'react-icons/fa';
import { ProductCard } from './ProductCard' import { ProductCard } from './ProductCard'
import { addItemToCart, CartState } from '@/utils/cartUtils' import { addItemToCart, CartState } from '@/utils/cartUtils'
import { BillingCycle, ProductDto } from '@/proxy/order/models' import { BillingCycle, ProductDto } from '@/proxy/order/models'
@ -86,7 +86,7 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
<aside className="lg:w-64 flex-shrink-0"> <aside className="lg:w-64 flex-shrink-0">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 sticky top-40"> <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 sticky top-40">
<div className="flex items-center space-x-2 mb-4"> <div className="flex items-center space-x-2 mb-4">
<Filter className="w-5 h-5 text-gray-600" /> <FaFilter className="w-5 h-5 text-gray-600" />
<h3 className="font-semibold text-gray-900">Kategoriler</h3> <h3 className="font-semibold text-gray-900">Kategoriler</h3>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
@ -117,11 +117,11 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
{/* Search input moved here */} {/* Search input moved here */}
<div className="mt-6"> <div className="mt-6">
<div className="flex items-center space-x-2 mb-3"> <div className="flex items-center space-x-2 mb-3">
<Search className="w-5 h-5 text-gray-600" /> <FaSearch className="w-5 h-5 text-gray-600" />
<h3 className="font-semibold text-gray-900">Arama</h3> <h3 className="font-semibold text-gray-900">Arama</h3>
</div> </div>
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<input <input
type="text" type="text"
placeholder="Ürün ara..." placeholder="Ürün ara..."
@ -154,7 +154,7 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
{filteredProducts.length === 0 && ( {filteredProducts.length === 0 && (
<div className="text-center py-12"> <div className="text-center py-12">
<div className="text-gray-400 mb-2"> <div className="text-gray-400 mb-2">
<Filter className="w-12 h-12 mx-auto" /> <FaFilter className="w-12 h-12 mx-auto" />
</div> </div>
<h3 className="text-lg font-medium text-gray-900 mb-2">Ürün bulunamadı</h3> <h3 className="text-lg font-medium text-gray-900 mb-2">Ürün bulunamadı</h3>
<p className="text-gray-600">Arama kriterlerinizi değiştirmeyi deneyin.</p> <p className="text-gray-600">Arama kriterlerinizi değiştirmeyi deneyin.</p>

View file

@ -1,20 +1,20 @@
import { getTenantByNameDetail } from '@/services/tenant.service' import { getTenantByNameDetail } from '@/services/tenant.service'
import { CustomTenantDto } from '@/proxy/config/models' import { CustomTenantDto } from '@/proxy/config/models'
import { import {
ArrowLeft, FaArrowLeft,
ArrowRight, FaArrowRight,
BadgeDollarSign, FaDollarSign,
Banknote, FaMoneyBillWave,
Building, FaBuilding,
Globe, FaGlobe,
Mail, FaEnvelope,
Map, FaMap,
MapPin, FaMapPin,
Phone, FaPhone,
Search, FaSearch,
User, FaUser,
UserPlus, FaUserPlus,
} from 'lucide-react' } from 'react-icons/fa'
import React, { useState } from 'react' import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
@ -73,7 +73,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div className="w-full lg:w-1/3 bg-white rounded-xl shadow-lg border border-gray-200 p-6"> <div className="w-full lg:w-1/3 bg-white rounded-xl shadow-lg border border-gray-200 p-6">
<div className="mb-6"> <div className="mb-6">
<h2 className="text-lg font-semibold mb-4 flex items-center"> <h2 className="text-lg font-semibold mb-4 flex items-center">
<User className="w-5 h-5 text-green-600 mr-2" /> Müşteri Bilgileri <FaUser className="w-5 h-5 text-green-600 mr-2" /> Müşteri Bilgileri
</h2> </h2>
</div> </div>
@ -114,7 +114,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<label className="block text-sm font-medium text-gray-700 mb-2">Kurum Kodu *</label> <label className="block text-sm font-medium text-gray-700 mb-2">Kurum Kodu *</label>
<div className="relative flex flex-col sm:flex-row sm:items-stretch"> <div className="relative flex flex-col sm:flex-row sm:items-stretch">
<div className="relative w-full"> <div className="relative w-full">
<Building className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -136,7 +136,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
onClick={getTenantInfo} onClick={getTenantInfo}
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-600 text-white rounded-lg sm:rounded-r-lg sm:rounded-l-none hover:bg-blue-700 transition-colors min-w-[148px]" className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-600 text-white rounded-lg sm:rounded-r-lg sm:rounded-l-none hover:bg-blue-700 transition-colors min-w-[148px]"
> >
<Search className="w-4 h-4" /> <FaSearch className="w-4 h-4" />
Kurumu Bul Kurumu Bul
</button> </button>
</div> </div>
@ -144,31 +144,31 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
{formData.institutionName && ( {formData.institutionName && (
<div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700 p-3"> <div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700 p-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<User className="w-4 h-4 text-gray-500" /> <FaUser className="w-4 h-4 text-gray-500" />
<span className="font-medium">Kurucu:</span> <span className="font-medium">Kurucu:</span>
<span>{formData.founder}</span> <span>{formData.founder}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Building className="w-4 h-4 text-gray-500" /> <FaBuilding className="w-4 h-4 text-gray-500" />
<span className="font-medium">Şirket:</span> <span className="font-medium">Şirket:</span>
<span>{formData.institutionName}</span> <span>{formData.institutionName}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Mail className="w-4 h-4 text-gray-500" /> <FaEnvelope className="w-4 h-4 text-gray-500" />
<span className="font-medium">E-posta:</span> <span className="font-medium">E-posta:</span>
<span>{formData.email}</span> <span>{formData.email}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Phone className="w-4 h-4 text-gray-500" /> <FaPhone className="w-4 h-4 text-gray-500" />
<span className="font-medium">Mobile:</span> <span className="font-medium">Mobile:</span>
<span>{formData.mobile}</span> <span>{formData.mobile}</span>
</div> </div>
<div className="flex items-start gap-2"> <div className="flex items-start gap-2">
<MapPin className="w-4 h-4 text-gray-500 mt-0.5" /> <FaMapPin className="w-4 h-4 text-gray-500 mt-0.5" />
<div> <div>
<span className="font-medium">Adres:</span> <span className="font-medium">Adres:</span>
<div>{formData.address}</div> <div>{formData.address}</div>
@ -176,44 +176,44 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Globe className="w-4 h-4 text-gray-500" /> <FaGlobe className="w-4 h-4 text-gray-500" />
<span className="font-medium">Ülke:</span> <span className="font-medium">Ülke:</span>
<span>{formData.country}</span> <span>{formData.country}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Globe className="w-4 h-4 text-gray-500" /> <FaGlobe className="w-4 h-4 text-gray-500" />
<span className="font-medium">Şehir:</span> <span className="font-medium">Şehir:</span>
<span>{formData.city}</span> <span>{formData.city}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Map className="w-4 h-4 text-gray-500" /> <FaMap className="w-4 h-4 text-gray-500" />
<span className="font-medium">İlçe:</span> <span className="font-medium">İlçe:</span>
<span>{formData.district}</span> <span>{formData.district}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<MapPin className="w-4 h-4 text-gray-500" /> <FaMapPin className="w-4 h-4 text-gray-500" />
<span className="font-medium">Posta Kodu:</span> <span className="font-medium">Posta Kodu:</span>
<span>{formData.postalCode}</span> <span>{formData.postalCode}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Banknote className="w-4 h-4 text-gray-500" /> <FaMoneyBillWave className="w-4 h-4 text-gray-500" />
<span className="font-medium">Vergi Dairesi:</span> <span className="font-medium">Vergi Dairesi:</span>
<span>{formData.taxOffice}</span> <span>{formData.taxOffice}</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<BadgeDollarSign className="w-4 h-4 text-gray-500" /> <FaDollarSign className="w-4 h-4 text-gray-500" />
<span className="font-medium">Vergi No:</span> <span className="font-medium">Vergi No:</span>
<span>{formData.vknTckn}</span> <span>{formData.vknTckn}</span>
</div> </div>
{formData.reference && ( {formData.reference && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<UserPlus className="w-4 h-4 text-gray-500" /> <FaUserPlus className="w-4 h-4 text-gray-500" />
<span className="font-medium">Referans:</span> <span className="font-medium">Referans:</span>
<span>{formData.reference}</span> <span>{formData.reference}</span>
</div> </div>
@ -229,7 +229,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
Şirket Adı * Şirket Adı *
</label> </label>
<div className="relative"> <div className="relative">
<Building className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -244,7 +244,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Kurucu *</label> <label className="text-sm font-medium text-gray-700">Kurucu *</label>
<div className="relative"> <div className="relative">
<User className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaUser className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -261,7 +261,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Telefon *</label> <label className="text-sm font-medium text-gray-700">Telefon *</label>
<div className="relative"> <div className="relative">
<Phone className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaPhone className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="tel" type="tel"
required required
@ -275,7 +275,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">E-posta *</label> <label className="text-sm font-medium text-gray-700">E-posta *</label>
<div className="relative"> <div className="relative">
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaEnvelope className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="email" type="email"
required required
@ -291,7 +291,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Adres *</label> <label className="text-sm font-medium text-gray-700">Adres *</label>
<div className="relative"> <div className="relative">
<MapPin className="absolute left-3 top-3 text-gray-400 w-5 h-5" /> <FaMapPin className="absolute left-3 top-3 text-gray-400 w-5 h-5" />
<textarea <textarea
required required
placeholder="Enter your address" placeholder="Enter your address"
@ -307,7 +307,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Ülke</label> <label className="text-sm font-medium text-gray-700">Ülke</label>
<div className="relative"> <div className="relative">
<Globe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaGlobe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
placeholder="Türkiye" placeholder="Türkiye"
@ -320,7 +320,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Şehir *</label> <label className="text-sm font-medium text-gray-700">Şehir *</label>
<div className="relative"> <div className="relative">
<Globe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaGlobe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -337,7 +337,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">İlçe *</label> <label className="text-sm font-medium text-gray-700">İlçe *</label>
<div className="relative"> <div className="relative">
<Map className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaMapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -351,7 +351,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Posta Kodu *</label> <label className="text-sm font-medium text-gray-700">Posta Kodu *</label>
<div className="relative"> <div className="relative">
<MapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaMapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -368,7 +368,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Vergi Dairesi *</label> <label className="text-sm font-medium text-gray-700">Vergi Dairesi *</label>
<div className="relative"> <div className="relative">
<Banknote className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -382,7 +382,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Vergi No *</label> <label className="text-sm font-medium text-gray-700">Vergi No *</label>
<div className="relative"> <div className="relative">
<BadgeDollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaDollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
required required
@ -398,7 +398,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<div> <div>
<label className="text-sm font-medium text-gray-700">Referans</label> <label className="text-sm font-medium text-gray-700">Referans</label>
<div className="relative"> <div className="relative">
<UserPlus className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" /> <FaUserPlus className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input <input
type="text" type="text"
placeholder="Referans kişi veya kodu" placeholder="Referans kişi veya kodu"
@ -417,14 +417,14 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
onClick={() => navigate('/products')} onClick={() => navigate('/products')}
className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg" className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg"
> >
<ArrowLeft className="w-4 h-4 mr-2" /> <FaArrowLeft className="w-4 h-4 mr-2" />
Geri Geri
</button> </button>
<button <button
type="submit" type="submit"
className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg" className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg"
> >
<ArrowRight className="w-5 h-5 mr-2" /> <FaArrowRight className="w-5 h-5 mr-2" />
Devam Et Devam Et
</button> </button>
</div> </div>

View file

@ -2,9 +2,14 @@ import React, { useState, useMemo, useEffect } from 'react'
import { TemplateEditor } from '../reports/TemplateEditor' import { TemplateEditor } from '../reports/TemplateEditor'
import { ReportGenerator } from '../reports/ReportGenerator' import { ReportGenerator } from '../reports/ReportGenerator'
import { TemplateCard } from './TemplateCard' import { TemplateCard } from './TemplateCard'
import { Button } from '../ui/Button' import { Button, Input} from '../ui'
import { Input } from '../ui/Input' import {
import { Plus, Search, Filter, FileText, BarChart3 } from 'lucide-react' FaPlus,
FaSearch,
FaFilter,
FaFileAlt,
FaChartBar
} from 'react-icons/fa';
import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models' import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models'
import { useReports } from '@/utils/hooks/useReports' import { useReports } from '@/utils/hooks/useReports'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -187,7 +192,7 @@ export const Dashboard: React.FC = () => {
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
{/* Search Input */} {/* Search Input */}
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
<Input <Input
placeholder="Şablon ara..." placeholder="Şablon ara..."
value={searchQuery} value={searchQuery}
@ -202,7 +207,7 @@ export const Dashboard: React.FC = () => {
onClick={handleCreateTemplate} onClick={handleCreateTemplate}
className="bg-blue-600 hover:bg-blue-700 font-medium px-6 py-2.5 rounded-lg shadow-md hover:shadow-lg transition-all duration-200 flex items-center space-x-2" className="bg-blue-600 hover:bg-blue-700 font-medium px-6 py-2.5 rounded-lg shadow-md hover:shadow-lg transition-all duration-200 flex items-center space-x-2"
> >
<Plus className="h-5 w-5" /> <FaPlus className="h-5 w-5" />
<span>Yeni Şablon</span> <span>Yeni Şablon</span>
</Button> </Button>
</div> </div>
@ -219,7 +224,7 @@ export const Dashboard: React.FC = () => {
<p className="text-2xl font-bold text-gray-900">{filteredTemplates.length}</p> <p className="text-2xl font-bold text-gray-900">{filteredTemplates.length}</p>
</div> </div>
<div className="bg-blue-100 p-3 rounded-full"> <div className="bg-blue-100 p-3 rounded-full">
<FileText className="h-6 w-6 text-blue-600" /> <FaFileAlt className="h-6 w-6 text-blue-600" />
</div> </div>
</div> </div>
</div> </div>
@ -231,7 +236,7 @@ export const Dashboard: React.FC = () => {
<p className="text-2xl font-bold text-gray-900">{categories.length}</p> <p className="text-2xl font-bold text-gray-900">{categories.length}</p>
</div> </div>
<div className="bg-emerald-100 p-3 rounded-full"> <div className="bg-emerald-100 p-3 rounded-full">
<Filter className="h-6 w-6 text-emerald-600" /> <FaFilter className="h-6 w-6 text-emerald-600" />
</div> </div>
</div> </div>
</div> </div>
@ -247,7 +252,7 @@ export const Dashboard: React.FC = () => {
</p> </p>
</div> </div>
<div className="bg-purple-100 p-3 rounded-full"> <div className="bg-purple-100 p-3 rounded-full">
<BarChart3 className="h-6 w-6 text-purple-600" /> <FaChartBar className="h-6 w-6 text-purple-600" />
</div> </div>
</div> </div>
</div> </div>
@ -256,7 +261,7 @@ export const Dashboard: React.FC = () => {
{/* Templates Grid */} {/* Templates Grid */}
{filteredTemplates.length === 0 ? ( {filteredTemplates.length === 0 ? (
<div className="bg-white rounded-xl shadow-md p-12 border border-gray-200 text-center"> <div className="bg-white rounded-xl shadow-md p-12 border border-gray-200 text-center">
<FileText className="h-16 w-16 text-gray-400 mx-auto mb-4" /> <FaFileAlt className="h-16 w-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2"> <h3 className="text-lg font-medium text-gray-900 mb-2">
{templates.length === 0 ? 'Henüz şablon oluşturulmamış' : 'Şablon bulunamadı'} {templates.length === 0 ? 'Henüz şablon oluşturulmamış' : 'Şablon bulunamadı'}
</h3> </h3>

View file

@ -1,9 +1,7 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Button } from '../ui/Button' import { Button, Input, Dialog } from '../ui'
import { Input } from '../ui/Input' import { FaFileAlt } from 'react-icons/fa';
import { FileText } from 'lucide-react'
import { ReportTemplateDto } from '@/proxy/reports/models' import { ReportTemplateDto } from '@/proxy/reports/models'
import { Dialog } from '../ui'
interface ReportGeneratorProps { interface ReportGeneratorProps {
isOpen: boolean isOpen: boolean
@ -109,7 +107,7 @@ export const ReportGenerator: React.FC<ReportGeneratorProps> = ({
</div> </div>
) : ( ) : (
<div className="py-8 text-gray-500"> <div className="py-8 text-gray-500">
<FileText className="h-12 w-12 text-gray-400 mx-auto mb-4" /> <FaFileAlt className="h-12 w-12 text-gray-400 mx-auto mb-4" />
<p>Bu şablon için parametre tanımlanmamış.</p> <p>Bu şablon için parametre tanımlanmamış.</p>
<p className="text-sm">Direkt rapor oluşturabilirsiniz.</p> <p className="text-sm">Direkt rapor oluşturabilirsiniz.</p>
</div> </div>
@ -123,7 +121,7 @@ export const ReportGenerator: React.FC<ReportGeneratorProps> = ({
className="bg-blue-600 hover:bg-blue-700 font-medium px-2 sm:px-3 py-1.5 rounded text-xs flex items-center gap-1" className="bg-blue-600 hover:bg-blue-700 font-medium px-2 sm:px-3 py-1.5 rounded text-xs flex items-center gap-1"
> >
<FileText className="h-4 w-4 mr-2" /> <FaFileAlt className="h-4 w-4 mr-2" />
{isGenerating ? 'Oluşturuluyor...' : 'Rapor Oluştur'} {isGenerating ? 'Oluşturuluyor...' : 'Rapor Oluştur'}
</Button> </Button>
</div> </div>

View file

@ -1,7 +1,14 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { useParams, useNavigate } from 'react-router-dom' import { useParams, useNavigate } from 'react-router-dom'
import { Button } from '../ui/Button' import { Button } from '../ui/Button'
import { ArrowLeft, Calendar, FileText, Download, ZoomIn, ZoomOut } from 'lucide-react' import {
FaArrowLeft,
FaCalendarAlt,
FaFileAlt,
FaDownload,
FaSearchPlus,
FaSearchMinus,
} from 'react-icons/fa'
import html2canvas from 'html2canvas' import html2canvas from 'html2canvas'
import jsPDF from 'jspdf' import jsPDF from 'jspdf'
import { ReportGeneratedDto, ReportTemplateDto } from '@/proxy/reports/models' import { ReportGeneratedDto, ReportTemplateDto } from '@/proxy/reports/models'
@ -131,7 +138,7 @@ export const ReportViewer: React.FC = () => {
<div className="text-center"> <div className="text-center">
<h1 className="text-2xl font-bold text-gray-900 mb-4">{error || 'Rapor bulunamadı'}</h1> <h1 className="text-2xl font-bold text-gray-900 mb-4">{error || 'Rapor bulunamadı'}</h1>
<Button onClick={() => navigate(ROUTES_ENUM.protected.dashboard)}> <Button onClick={() => navigate(ROUTES_ENUM.protected.dashboard)}>
<ArrowLeft className="h-4 w-4 mr-2" /> <FaArrowLeft className="h-4 w-4 mr-2" />
Ana Sayfaya Dön Ana Sayfaya Dön
</Button> </Button>
</div> </div>
@ -145,7 +152,7 @@ export const ReportViewer: React.FC = () => {
<div className="text-center"> <div className="text-center">
<h1 className="text-2xl font-bold text-gray-900 mb-4">Rapor bulunamadı</h1> <h1 className="text-2xl font-bold text-gray-900 mb-4">Rapor bulunamadı</h1>
<Button onClick={() => navigate(ROUTES_ENUM.protected.dashboard)}> <Button onClick={() => navigate(ROUTES_ENUM.protected.dashboard)}>
<ArrowLeft className="h-4 w-4 mr-2" /> <FaArrowLeft className="h-4 w-4 mr-2" />
Ana Sayfaya Dön Ana Sayfaya Dön
</Button> </Button>
</div> </div>
@ -163,7 +170,7 @@ export const ReportViewer: React.FC = () => {
Aradığınız rapor mevcut değil veya silinmiş olabilir. Aradığınız rapor mevcut değil veya silinmiş olabilir.
</p> </p>
<Button onClick={() => navigate(ROUTES_ENUM.protected.dashboard)}> <Button onClick={() => navigate(ROUTES_ENUM.protected.dashboard)}>
<ArrowLeft className="h-4 w-4 mr-2" /> <FaArrowLeft className="h-4 w-4 mr-2" />
Ana Sayfaya Dön Ana Sayfaya Dön
</Button> </Button>
</div> </div>
@ -242,7 +249,7 @@ export const ReportViewer: React.FC = () => {
<h1 className="text-lg font-semibold text-gray-900">{report.templateName}</h1> <h1 className="text-lg font-semibold text-gray-900">{report.templateName}</h1>
<div className="flex items-center space-x-4 text-sm text-gray-500"> <div className="flex items-center space-x-4 text-sm text-gray-500">
<span className="flex items-center"> <span className="flex items-center">
<Calendar className="h-4 w-4 mr-1" /> <FaCalendarAlt className="h-4 w-4 mr-1" />
{new Date(report.generatedAt).toLocaleDateString('tr-TR', { {new Date(report.generatedAt).toLocaleDateString('tr-TR', {
year: 'numeric', year: 'numeric',
month: 'long', month: 'long',
@ -253,7 +260,7 @@ export const ReportViewer: React.FC = () => {
</span> </span>
{template && ( {template && (
<span className="flex items-center"> <span className="flex items-center">
<FileText className="h-4 w-4 mr-1" /> <FaFileAlt className="h-4 w-4 mr-1" />
{template.categoryName} {template.categoryName}
</span> </span>
)} )}
@ -263,23 +270,25 @@ export const ReportViewer: React.FC = () => {
<div className="flex items-center space-x-2 flex-shrink-0"> <div className="flex items-center space-x-2 flex-shrink-0">
<Button variant="solid" onClick={handleZoomOut} disabled={zoomLevel <= 50} size="sm"> <Button variant="solid" onClick={handleZoomOut} disabled={zoomLevel <= 50} size="sm">
<ZoomOut className="h-4 w-4" /> <FaSearchMinus className="h-4 w-4" />
</Button> </Button>
<span className="text-sm text-gray-600 px-2 min-w-[4rem] text-center"> <span className="text-sm text-gray-600 px-2 min-w-[4rem] text-center">
{zoomLevel}% {zoomLevel}%
</span> </span>
<Button variant="solid" onClick={handleZoomIn} disabled={zoomLevel >= 200} size="sm"> <Button variant="solid" onClick={handleZoomIn} disabled={zoomLevel >= 200} size="sm">
<ZoomIn className="h-4 w-4" /> <FaSearchPlus className="h-4 w-4" />
</Button> </Button>
<div className="w-px h-6 bg-gray-300 mx-2"></div> <div className="w-px h-6 bg-gray-300 mx-2"></div>
<Button <Button
onClick={handleDownloadPdf} onClick={handleDownloadPdf}
className="bg-white-600 hover:bg-white-700 font-medium px-2 sm:px-3 py-1.5 rounded text-xs flex items-center gap-1" className="bg-white-600 hover:bg-white-700 font-medium px-2 sm:px-3 py-1.5 rounded text-xs flex items-center gap-1"
> >
<Download className="h-4 w-4 mr-2" /> <FaDownload className="h-4 w-4 mr-2" />
PDF İndir PDF İndir
</Button> </Button>
<Button variant="solid" onClick={handlePrint}>Yazdır</Button> <Button variant="solid" onClick={handlePrint}>
Yazdır
</Button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import { Button } from '../ui/Button' import { Button } from '../ui/Button'
import { FileText, Edit, Trash2, Play } from 'lucide-react' import { FaFileAlt, FaEdit, FaTrash, FaPlay } from 'react-icons/fa';
import { ReportTemplateDto } from '@/proxy/reports/models' import { ReportTemplateDto } from '@/proxy/reports/models'
interface TemplateCardProps { interface TemplateCardProps {
@ -27,7 +27,7 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
</div> </div>
<div className="flex items-center gap-1 flex-shrink-0 bg-gray-50 px-2 py-1 rounded-lg"> <div className="flex items-center gap-1 flex-shrink-0 bg-gray-50 px-2 py-1 rounded-lg">
<FileText className="h-4 w-4 text-blue-500" /> <FaFileAlt className="h-4 w-4 text-blue-500" />
<span className="text-xs text-gray-500 whitespace-nowrap">{template.parameters.length}</span> <span className="text-xs text-gray-500 whitespace-nowrap">{template.parameters.length}</span>
</div> </div>
</div> </div>
@ -69,7 +69,7 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
onClick={() => onGenerate(template)} onClick={() => onGenerate(template)}
className="bg-gray-600 hover:bg-gray-700 font-medium px-3 py-1.5 rounded text-xs flex items-center gap-1 flex-1 justify-center min-w-0" className="bg-gray-600 hover:bg-gray-700 font-medium px-3 py-1.5 rounded text-xs flex items-center gap-1 flex-1 justify-center min-w-0"
> >
<Play className="h-3 w-3" /> <FaPlay className="h-3 w-3" />
<span className="truncate">Göster</span> <span className="truncate">Göster</span>
</Button> </Button>
@ -79,7 +79,7 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
onClick={() => onEdit(template)} onClick={() => onEdit(template)}
className="font-medium px-3 py-1.5 rounded text-xs flex items-center gap-1 flex-1 justify-center min-w-0" className="font-medium px-3 py-1.5 rounded text-xs flex items-center gap-1 flex-1 justify-center min-w-0"
> >
<Edit className="h-3 w-3" /> <FaEdit className="h-3 w-3" />
<span className="truncate">Düzenle</span> <span className="truncate">Düzenle</span>
</Button> </Button>
@ -89,7 +89,7 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
onClick={() => onDelete(template.id)} onClick={() => onDelete(template.id)}
className="bg-red-600 hover:bg-red-700 font-medium px-3 py-1.5 rounded text-xs flex items-center justify-center flex-1 min-w-0" className="bg-red-600 hover:bg-red-700 font-medium px-3 py-1.5 rounded text-xs flex items-center justify-center flex-1 min-w-0"
> >
<Trash2 className="h-3 w-3" /> <FaTrash className="h-3 w-3" />
<span className="truncate">Sil</span> <span className="truncate">Sil</span>
</Button> </Button>
</div> </div>

View file

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { Save, X, FileText, Code, Settings } from 'lucide-react' import { FaSave, FaTimes, FaFileAlt, FaCode, FaCog } from 'react-icons/fa'
import { ReportHtmlEditor } from './ReportHtmlEditor' import { ReportHtmlEditor } from './ReportHtmlEditor'
import { ReportParameterDto, ReportTemplateDto, ReportCategoryDto } from '@/proxy/reports/models' import { ReportParameterDto, ReportTemplateDto, ReportCategoryDto } from '@/proxy/reports/models'
import { Button, Input, Dialog } from '../ui' import { Button, Input, Dialog } from '../ui'
@ -132,15 +132,15 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
setFormData((prev) => ({ setFormData((prev) => ({
...prev, ...prev,
parameters: prev.parameters.map((param) => parameters: prev.parameters.map((param) =>
param.id === paramId ? { ...param, ...updates } : param param.id === paramId ? { ...param, ...updates } : param,
), ),
})) }))
} }
const tabs = [ const tabs = [
{ id: 'info', label: translate('::Şablon Bilgileri'), icon: FileText }, { id: 'info', label: translate('::Şablon Bilgileri'), icon: FaFileAlt },
{ id: 'parameters', label: translate('::Parametreler'), icon: Settings }, { id: 'parameters', label: translate('::Parametreler'), icon: FaCog },
{ id: 'content', label: translate('::HTML İçerik'), icon: Code }, { id: 'content', label: translate('::HTML İçerik'), icon: FaCode },
] ]
return ( return (
@ -250,7 +250,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
onClick={() => removeTag(tag)} onClick={() => removeTag(tag)}
className="ml-2 text-blue-600 hover:text-blue-800" className="ml-2 text-blue-600 hover:text-blue-800"
> >
<X className="h-3 w-3" /> <FaTimes className="h-3 w-3" />
</button> </button>
</span> </span>
))} ))}
@ -303,7 +303,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
<div className="max-w-full mx-auto"> <div className="max-w-full mx-auto">
{formData.parameters.length === 0 ? ( {formData.parameters.length === 0 ? (
<div className="text-center py-12"> <div className="text-center py-12">
<Settings className="h-16 w-16 text-gray-400 mx-auto mb-4" /> <FaCog className="h-16 w-16 text-gray-400 mx-auto mb-4" />
<p className="text-gray-500 text-lg mb-2">Henüz parametre algılanmadı</p> <p className="text-gray-500 text-lg mb-2">Henüz parametre algılanmadı</p>
<p className="text-gray-400 text-sm"> <p className="text-gray-400 text-sm">
HTML içeriğinde @@PARAMETRE formatında parametreler kullandığınızda burada HTML içeriğinde @@PARAMETRE formatında parametreler kullandığınızda burada
@ -326,7 +326,9 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
</div> </div>
<select <select
value={param.type} value={param.type}
onChange={(e) => updateParameter(param.id, { type: e.target.value as any })} onChange={(e) =>
updateParameter(param.id, { type: e.target.value as any })
}
className="text-xs bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded-full flex-shrink-0 ml-1 border-none outline-none cursor-pointer" className="text-xs bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded-full flex-shrink-0 ml-1 border-none outline-none cursor-pointer"
> >
<option value="text">text</option> <option value="text">text</option>
@ -336,12 +338,14 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
<option value="checkbox">checkbox</option> <option value="checkbox">checkbox</option>
</select> </select>
</div> </div>
<div className="mb-2"> <div className="mb-2">
<input <input
type="text" type="text"
value={param.description || ''} value={param.description || ''}
onChange={(e) => updateParameter(param.id, { description: e.target.value })} onChange={(e) =>
updateParameter(param.id, { description: e.target.value })
}
placeholder="Parametre açıklaması" placeholder="Parametre açıklaması"
className="w-full text-xs text-gray-600 bg-transparent border-none outline-none resize-none" className="w-full text-xs text-gray-600 bg-transparent border-none outline-none resize-none"
/> />
@ -351,7 +355,9 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
<input <input
type="text" type="text"
value={param.defaultValue || ''} value={param.defaultValue || ''}
onChange={(e) => updateParameter(param.id, { defaultValue: e.target.value })} onChange={(e) =>
updateParameter(param.id, { defaultValue: e.target.value })
}
placeholder="Varsayılan değer" placeholder="Varsayılan değer"
className="w-full text-xs bg-gray-50 px-1.5 py-0.5 rounded border border-gray-200 outline-none" className="w-full text-xs bg-gray-50 px-1.5 py-0.5 rounded border border-gray-200 outline-none"
/> />
@ -362,7 +368,9 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={param.required} checked={param.required}
onChange={(e) => updateParameter(param.id, { required: e.target.checked })} onChange={(e) =>
updateParameter(param.id, { required: e.target.checked })
}
className="w-3 h-3 text-red-600 rounded border-gray-300 focus:ring-red-500" className="w-3 h-3 text-red-600 rounded border-gray-300 focus:ring-red-500"
/> />
<span className="text-xs text-gray-600">Zorunlu</span> <span className="text-xs text-gray-600">Zorunlu</span>
@ -388,7 +396,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
onClick={handleSave} onClick={handleSave}
className="bg-blue-600 hover:bg-blue-700 font-medium px-2 py-2 rounded-lg shadow-md hover:shadow-lg transition-all duration-200 flex items-center space-x-2" className="bg-blue-600 hover:bg-blue-700 font-medium px-2 py-2 rounded-lg shadow-md hover:shadow-lg transition-all duration-200 flex items-center space-x-2"
> >
<Save className="h-5 w-5" /> <FaSave className="h-5 w-5" />
{isSaving ? 'Kaydediliyor...' : template ? 'Güncelle' : 'Kaydet'} {isSaving ? 'Kaydediliyor...' : template ? 'Güncelle' : 'Kaydet'}
</Button> </Button>
</div> </div>

View file

@ -1,5 +1,7 @@
import navigationIcon from '@/configs/navigation-icon.config' import navigationIcon from '@/configs/navigation-icon.config'
import type { ElementType, ComponentPropsWithRef } from 'react' import type { ElementType, ComponentPropsWithRef } from 'react'
import React from 'react'
import { FaQuestionCircle } from 'react-icons/fa'
type HorizontalMenuIconProps = { type HorizontalMenuIconProps = {
icon: string icon: string
@ -16,11 +18,14 @@ export const Icon = <T extends ElementType>({
} }
const HorizontalMenuIcon = ({ icon }: HorizontalMenuIconProps) => { const HorizontalMenuIcon = ({ icon }: HorizontalMenuIconProps) => {
if (typeof icon !== 'string' && !icon) { if (typeof icon !== 'string' || !icon) {
return <></> return <></>
} }
return <span className="text-xl ltr:mr-2 rtl:ml-2">{navigationIcon[icon]}</span> // React.createElement ile dinamik ikon bileşenini render et
const IconComponent = navigationIcon[icon] || FaQuestionCircle // fallback ikon
return <span className="text-xl ltr:mr-2 rtl:ml-2">{React.createElement(IconComponent)}</span>
} }
export default HorizontalMenuIcon export default HorizontalMenuIcon

View file

@ -2,6 +2,8 @@ import navigationIcon from '@/configs/navigation-icon.config'
import MenuItem from '@/components/ui/MenuItem' import MenuItem from '@/components/ui/MenuItem'
import HorizontalMenuNavLink from './HorizontalMenuNavLink' import HorizontalMenuNavLink from './HorizontalMenuNavLink'
import type { NavMode } from '@/@types/theme' import type { NavMode } from '@/@types/theme'
import React from 'react'
import { FaQuestionCircle } from 'react-icons/fa'
export type HorizontalMenuItemProps = { export type HorizontalMenuItemProps = {
nav: { nav: {
@ -19,7 +21,9 @@ export type HorizontalMenuItemProps = {
const HorizontalMenuItem = ({ nav, isLink, manuVariant }: HorizontalMenuItemProps) => { const HorizontalMenuItem = ({ nav, isLink, manuVariant }: HorizontalMenuItemProps) => {
const { title, icon, path, isExternalLink } = nav const { title, icon, path, isExternalLink } = nav
const renderIcon = icon && <span className="text-2xl">{navigationIcon[icon]}</span> // Dinamik ikon render etmek için createElement kullanıyoruz
const renderIcon =
icon && React.createElement(navigationIcon[icon] || FaQuestionCircle, { className: 'text-2xl' })
return ( return (
<> <>

View file

@ -16,7 +16,9 @@ import {
import { useStoreState } from '@/store' import { useStoreState } from '@/store'
import useMenuActive from '@/utils/hooks/useMenuActive' import useMenuActive from '@/utils/hooks/useMenuActive'
import isEmpty from 'lodash/isEmpty' import isEmpty from 'lodash/isEmpty'
import React from 'react'
import { useEffect } from 'react' import { useEffect } from 'react'
import { FaQuestionCircle } from 'react-icons/fa'
import { Link, useLocation } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
export type SelectedMenuItem = { export type SelectedMenuItem = {
@ -116,7 +118,9 @@ const StackedSideNavMini = (props: StackedSideNavMiniProps) => {
}) })
} }
> >
<div className="text-2xl">{navigationIcon[nav.icon]}</div> <div className="text-2xl">
{React.createElement(navigationIcon[nav.icon] || FaQuestionCircle)}{' '}
</div>
</Menu.MenuItem> </Menu.MenuItem>
) : ( ) : (
<Link <Link
@ -129,7 +133,9 @@ const StackedSideNavMini = (props: StackedSideNavMiniProps) => {
} }
> >
<Menu.MenuItem icon={nav.icon} eventKey={nav.key} className="mb-2"> <Menu.MenuItem icon={nav.icon} eventKey={nav.key} className="mb-2">
<div className="text-2xl">{navigationIcon[nav.icon]}</div> <div className="text-2xl">
{React.createElement(navigationIcon[nav.icon] || FaQuestionCircle)}
</div>
</Menu.MenuItem> </Menu.MenuItem>
</Link> </Link>
)} )}

View file

@ -1,5 +1,6 @@
import navigationIcon from '@/configs/navigation-icon.config' import navigationIcon from '@/configs/navigation-icon.config'
import type { ElementType, ComponentPropsWithRef } from 'react' import type { ElementType, ComponentPropsWithRef } from 'react'
import React from 'react'
type VerticalMenuIconProps = { type VerticalMenuIconProps = {
icon: string icon: string
@ -16,11 +17,23 @@ export const Icon = <T extends ElementType>({
} }
const VerticalMenuIcon = ({ icon }: VerticalMenuIconProps) => { const VerticalMenuIcon = ({ icon }: VerticalMenuIconProps) => {
if (typeof icon !== 'string' && !icon) { // Eğer icon boş veya string değilse, boş bir öğe döndür
if (typeof icon !== 'string' || !icon) {
return <></> return <></>
} }
return <span className="text-2xl ltr:mr-2 rtl:ml-2">{navigationIcon[icon]}</span> // navigationIcon'dan ikonu al ve React.createElement ile render et
const IconComponent = navigationIcon[icon]
if (!IconComponent) {
return <></> // İkon bulunamazsa, boş döndür
}
return (
<span className="text-2xl ltr:mr-2 rtl:ml-2">
{React.createElement(IconComponent)} {/* İkonu dinamik olarak render et */}
</span>
)
} }
export default VerticalMenuIcon export default VerticalMenuIcon

View file

@ -1,17 +1,18 @@
import { createElement } from 'react'
import * as fc from 'react-icons/fc' import * as fc from 'react-icons/fc'
import * as fa from 'react-icons/fa' import * as fa from 'react-icons/fa'
export type NavigationIcons = Record<string, JSX.Element> export type NavigationIcons = Record<string, React.ComponentType<any>>;
const navigationIcon: NavigationIcons = {} const navigationIcon: NavigationIcons = {};
for (const icon of Object.entries(fc)) { // fc (Font Awesome) ikonlarıyla dinamik olarak navigationIcon nesnesini doldur
navigationIcon[icon[0]] = createElement(icon[1]) for (const [key, Icon] of Object.entries(fc)) {
navigationIcon[key] = Icon; // Icon bileşenini doğrudan kullanıyoruz
} }
for (const icon of Object.entries(fa)) { // fa (Font Awesome) ikonlarıyla navigationIcon nesnesini doldur
navigationIcon[icon[0]] = createElement(icon[1]) for (const [key, Icon] of Object.entries(fa)) {
navigationIcon[key] = Icon; // Icon bileşenini doğrudan kullanıyoruz
} }
export default navigationIcon export default navigationIcon;

View file

@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect, SyntheticEvent } from 'react' import React, { useState, useRef, useEffect, SyntheticEvent } from 'react'
import { Bot } from 'lucide-react' import { FaRobot } from 'react-icons/fa';
import { useStoreActions, useStoreState } from '@/store' import { useStoreActions, useStoreState } from '@/store'
import { Avatar, Dropdown } from '@/components/ui' import { Avatar, Dropdown } from '@/components/ui'
import LoadAiPostsFromLocalStorage from './LoadAiPostsFromLocalStorage' import LoadAiPostsFromLocalStorage from './LoadAiPostsFromLocalStorage'
@ -276,7 +276,7 @@ const Assistant = () => {
<div className="flex-1 overflow-y-auto p-4 space-y-4"> <div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.length === 0 && ( {messages.length === 0 && (
<div className="text-center text-gray-500 mt-8"> <div className="text-center text-gray-500 mt-8">
<Bot className="w-12 h-12 mx-auto mb-4 text-gray-400" /> <FaRobot className="w-12 h-12 mx-auto mb-4 text-gray-400" />
<p className="mt-2">{translate('::AI.Welcome')}</p> <p className="mt-2">{translate('::AI.Welcome')}</p>
<p className="text-lg font-medium">{translate('::AI.Name')}</p> <p className="text-lg font-medium">{translate('::AI.Name')}</p>
</div> </div>
@ -293,7 +293,7 @@ const Assistant = () => {
{msg.role === 'user' ? ( {msg.role === 'user' ? (
<Avatar size={32} shape="circle" src={avatar} alt="avatar" /> <Avatar size={32} shape="circle" src={avatar} alt="avatar" />
) : ( ) : (
<Bot className="w-5 h-5 text-white" /> <FaRobot className="w-5 h-5 text-white" />
)} )}
</div> </div>
<div <div

View file

@ -9,6 +9,7 @@ import { GridColumnData } from '../list/GridColumnData'
import { useToolbar } from '../list/useToolbar' import { useToolbar } from '../list/useToolbar'
import { PermissionResults, RowMode } from './types' import { PermissionResults, RowMode } from './types'
import { GridDto } from '@/proxy/form/models' import { GridDto } from '@/proxy/form/models'
import React from 'react'
const FormButtons = (props: { const FormButtons = (props: {
mode: RowMode mode: RowMode
@ -108,8 +109,13 @@ const FormButtons = (props: {
key={'toolbarButton-' + i} key={'toolbarButton-' + i}
variant="default" variant="default"
size="sm" size="sm"
{...(item.options?.icon ? { icon: navigationIcon[item.options.icon] } : {})} {...(item.options?.icon
// title={translate(item.options.hint)} // TODO: translate('::' + item.options.hint) mu olmalı? ? {
icon: React.createElement(navigationIcon[item.options.icon], {
className: 'text-gray-400',
}),
}
: {})}
onClick={item.options.onClick} onClick={item.options.onClick}
> >
{item.options.text} {item.options.text}
@ -130,7 +136,13 @@ const FormButtons = (props: {
key={'commandColumnButton-' + i} key={'commandColumnButton-' + i}
variant="default" variant="default"
size="sm" size="sm"
{...(item.icon ? { icon: navigationIcon[item.icon] } : {})} {...(item.icon
? {
icon: React.createElement(navigationIcon[item.icon], {
className: 'text-gray-400',
}),
}
: {})}
title={item.hint} title={item.hint}
onClick={(e: any) => { onClick={(e: any) => {
if (item.onClick) { if (item.onClick) {

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Folder, MessageSquare, FileText, Plus, BarChart3 } from 'lucide-react' import { FaFolder, FaCommentAlt, FaFileAlt, FaChartBar } from 'react-icons/fa'
import { CategoryManagement } from './CategoryManagement' import { CategoryManagement } from './CategoryManagement'
import { TopicManagement } from './TopicManagement' import { TopicManagement } from './TopicManagement'
import { PostManagement } from './PostManagement' import { PostManagement } from './PostManagement'
@ -81,22 +81,22 @@ export function AdminView({
{ {
id: 'stats' as AdminSection, id: 'stats' as AdminSection,
label: translate('::App.Forum.Dashboard.Dashboard'), label: translate('::App.Forum.Dashboard.Dashboard'),
icon: BarChart3, icon: FaChartBar,
}, },
{ {
id: 'categories' as AdminSection, id: 'categories' as AdminSection,
label: translate('::App.Forum.Dashboard.Categories'), label: translate('::App.Forum.Dashboard.Categories'),
icon: Folder, icon: FaFolder,
}, },
{ {
id: 'topics' as AdminSection, id: 'topics' as AdminSection,
label: translate('::App.Forum.Dashboard.Topics'), label: translate('::App.Forum.Dashboard.Topics'),
icon: MessageSquare, icon: FaCommentAlt,
}, },
{ {
id: 'posts' as AdminSection, id: 'posts' as AdminSection,
label: translate('::App.Forum.Dashboard.Posts'), label: translate('::App.Forum.Dashboard.Posts'),
icon: FileText, icon: FaFileAlt,
}, },
] ]

View file

@ -1,5 +1,14 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Plus, Edit2, Trash2, Lock, Unlock, Eye, EyeOff, Loader2 } from 'lucide-react' import {
FaPlus,
FaEdit,
FaTrash,
FaLock,
FaUnlock,
FaEye,
FaEyeSlash,
FaSpinner,
} from 'react-icons/fa'
import { ForumCategory } from '@/proxy/forum/forum' import { ForumCategory } from '@/proxy/forum/forum'
import { useStoreState } from '@/store/store' import { useStoreState } from '@/store/store'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -161,7 +170,7 @@ export function CategoryManagement({
disabled={loading} disabled={loading}
className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50" className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
<span>{translate('::App.Forum.CategoryManagement.AddCategory')}</span> <span>{translate('::App.Forum.CategoryManagement.AddCategory')}</span>
</button> </button>
</div> </div>
@ -320,7 +329,7 @@ export function CategoryManagement({
{loading ? ( {loading ? (
<div className="p-8 text-center"> <div className="p-8 text-center">
<Loader2 className="w-8 h-8 animate-spin mx-auto mb-4 text-blue-600" /> <FaSpinner className="w-8 h-8 animate-spin mx-auto mb-4 text-blue-600" />
<p className="text-gray-500"> <p className="text-gray-500">
{translate('::App.Forum.CategoryManagement.Loadingcategories')} {translate('::App.Forum.CategoryManagement.Loadingcategories')}
</p> </p>
@ -368,9 +377,9 @@ export function CategoryManagement({
title={category.isActive ? 'Hide Category' : 'Show Category'} title={category.isActive ? 'Hide Category' : 'Show Category'}
> >
{category.isActive ? ( {category.isActive ? (
<Eye className="w-4 h-4" /> <FaEye className="w-4 h-4" />
) : ( ) : (
<EyeOff className="w-4 h-4" /> <FaEyeSlash className="w-4 h-4" />
)} )}
</button> </button>
@ -384,9 +393,9 @@ export function CategoryManagement({
title={category.isLocked ? 'Unlock Category' : 'Lock Category'} title={category.isLocked ? 'Unlock Category' : 'Lock Category'}
> >
{category.isLocked ? ( {category.isLocked ? (
<Lock className="w-4 h-4" /> <FaLock className="w-4 h-4" />
) : ( ) : (
<Unlock className="w-4 h-4" /> <FaUnlock className="w-4 h-4" />
)} )}
</button> </button>
@ -395,7 +404,7 @@ export function CategoryManagement({
className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors" className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors"
title={translate('::App.Forum.CategoryManagement.EditCategory')} title={translate('::App.Forum.CategoryManagement.EditCategory')}
> >
<Edit2 className="w-4 h-4" /> <FaEdit className="w-4 h-4" />
</button> </button>
<button <button
@ -403,7 +412,7 @@ export function CategoryManagement({
className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors" className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors"
title={translate('::App.Forum.CategoryManagement.DeleteCategory')} title={translate('::App.Forum.CategoryManagement.DeleteCategory')}
> >
<Trash2 className="w-4 h-4" /> <FaTrash className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -437,8 +446,7 @@ export function CategoryManagement({
setCategoryToDelete(null) setCategoryToDelete(null)
} }
}} }}
> ></ConfirmDialog>
</ConfirmDialog>
)} )}
</div> </div>
) )

View file

@ -1,4 +1,4 @@
import { Folder, MessageSquare, FileText, TrendingUp } from 'lucide-react' import { FaFolder, FaCommentDots, FaFileAlt, FaChartLine } from 'react-icons/fa';
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -31,28 +31,28 @@ export function AdminStats({ categories, topics, posts }: AdminStatsProps) {
title: translate('::App.Forum.Dashboard.TotalCategories'), title: translate('::App.Forum.Dashboard.TotalCategories'),
value: totalCategories, value: totalCategories,
subtitle: `${activeCategories} active`, subtitle: `${activeCategories} active`,
icon: Folder, icon: FaFolder,
color: 'bg-blue-500', color: 'bg-blue-500',
}, },
{ {
title: translate('::App.Forum.Dashboard.TotalTopics'), title: translate('::App.Forum.Dashboard.TotalTopics'),
value: totalTopics, value: totalTopics,
subtitle: `${solvedTopics} solved`, subtitle: `${solvedTopics} solved`,
icon: MessageSquare, icon: FaCommentDots,
color: 'bg-emerald-500', color: 'bg-emerald-500',
}, },
{ {
title: translate('::App.Forum.Dashboard.TotalPosts'), title: translate('::App.Forum.Dashboard.TotalPosts'),
value: totalPosts, value: totalPosts,
subtitle: `${acceptedAnswers} accepted answers`, subtitle: `${acceptedAnswers} accepted answers`,
icon: FileText, icon: FaFileAlt,
color: 'bg-orange-500', color: 'bg-orange-500',
}, },
{ {
title: translate('::App.Forum.Dashboard.EngagementRate'), title: translate('::App.Forum.Dashboard.EngagementRate'),
value: totalTopics > 0 ? Math.round((totalPosts / totalTopics) * 100) / 100 : 0, value: totalTopics > 0 ? Math.round((totalPosts / totalTopics) * 100) / 100 : 0,
subtitle: 'posts per topic', subtitle: 'posts per topic',
icon: TrendingUp, icon: FaChartLine,
color: 'bg-purple-500', color: 'bg-purple-500',
}, },
] ]

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Plus, Edit2, Trash2, CheckCircle, Circle, Heart, Loader2 } from 'lucide-react' import { FaPlus, FaEdit, FaTrashAlt, FaCheckCircle, FaCircle, FaHeart, FaSpinner } from 'react-icons/fa';
import { ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor' import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor'
import { useStoreState } from '@/store/store' import { useStoreState } from '@/store/store'
@ -169,7 +169,7 @@ export function PostManagement({
disabled={loading} disabled={loading}
className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50" className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
<span>{translate('::App.Forum.PostManagement.AddPost')}</span> <span>{translate('::App.Forum.PostManagement.AddPost')}</span>
</button> </button>
</div> </div>
@ -351,7 +351,7 @@ export function PostManagement({
{loading ? ( {loading ? (
<div className="p-8 text-center"> <div className="p-8 text-center">
<Loader2 className="w-8 h-8 animate-spin mx-auto mb-4 text-blue-600" /> <FaSpinner className="w-8 h-8 animate-spin mx-auto mb-4 text-blue-600" />
<p className="text-gray-500">{translate('::App.Forum.PostManagement.Loadingtopics')}</p> <p className="text-gray-500">{translate('::App.Forum.PostManagement.Loadingtopics')}</p>
</div> </div>
) : ( ) : (
@ -368,7 +368,7 @@ export function PostManagement({
<h4 className="text-sm font-semibold text-gray-900">{post.authorName}</h4> <h4 className="text-sm font-semibold text-gray-900">{post.authorName}</h4>
{post.isAcceptedAnswer && ( {post.isAcceptedAnswer && (
<div className="flex items-center space-x-1 bg-emerald-100 text-emerald-700 px-2 py-1 rounded-full text-xs"> <div className="flex items-center space-x-1 bg-emerald-100 text-emerald-700 px-2 py-1 rounded-full text-xs">
<CheckCircle className="w-3 h-3" /> <FaCheckCircle className="w-3 h-3" />
<span>Accepted Answer</span> <span>Accepted Answer</span>
</div> </div>
)} )}
@ -389,7 +389,7 @@ export function PostManagement({
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<span>{formatDate(post.creationTime)}</span> <span>{formatDate(post.creationTime)}</span>
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
<Heart className="w-4 h-4" /> <FaHeart className="w-4 h-4" />
<span>{post.likeCount} likes</span> <span>{post.likeCount} likes</span>
</div> </div>
</div> </div>
@ -411,9 +411,9 @@ export function PostManagement({
} }
> >
{post.isAcceptedAnswer ? ( {post.isAcceptedAnswer ? (
<CheckCircle className="w-4 h-4" /> <FaCheckCircle className="w-4 h-4" />
) : ( ) : (
<Circle className="w-4 h-4" /> <FaCircle className="w-4 h-4" />
)} )}
</button> </button>
@ -422,7 +422,7 @@ export function PostManagement({
className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors" className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors"
title={translate('::App.Forum.PostManagement.EditPost')} title={translate('::App.Forum.PostManagement.EditPost')}
> >
<Edit2 className="w-4 h-4" /> <FaEdit className="w-4 h-4" />
</button> </button>
<button <button
@ -430,7 +430,7 @@ export function PostManagement({
className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors" className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors"
title={translate('::App.Forum.PostManagement.DeletePost')} title={translate('::App.Forum.PostManagement.DeletePost')}
> >
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,17 +1,17 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { import {
Plus, FaPlus,
Edit2, FaEdit,
Trash2, FaTrashAlt,
Lock, FaLock,
Unlock, FaUnlock,
Pin, FaThumbtack,
PinOff, FaCheckCircle,
CheckCircle, FaCircle,
Circle, FaEye,
Eye, FaSpinner,
Loader2, FaTree,
} from 'lucide-react' } from 'react-icons/fa'
import { ForumCategory, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumTopic } from '@/proxy/forum/forum'
import { useStoreState } from '@/store/store' import { useStoreState } from '@/store/store'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -219,7 +219,7 @@ export function TopicManagement({
disabled={loading} disabled={loading}
className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50" className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
<span>{translate('::App.Forum.TopicManagement.AddTopic')}</span> <span>{translate('::App.Forum.TopicManagement.AddTopic')}</span>
</button> </button>
</div> </div>
@ -362,7 +362,7 @@ export function TopicManagement({
{loading ? ( {loading ? (
<div className="p-8 text-center"> <div className="p-8 text-center">
<Loader2 className="w-8 h-8 animate-spin mx-auto mb-4 text-blue-600" /> <FaSpinner className="w-8 h-8 animate-spin mx-auto mb-4 text-blue-600" />
<p className="text-gray-500"> <p className="text-gray-500">
{translate('::App.Forum.TopicManagement.Loadingtopics')} {translate('::App.Forum.TopicManagement.Loadingtopics')}
</p> </p>
@ -378,9 +378,9 @@ export function TopicManagement({
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
{topic.isPinned && <Pin className="w-4 h-4 text-orange-500" />} {topic.isPinned && <FaThumbtack className="w-4 h-4 text-orange-500" />}
{topic.isLocked && <Lock className="w-4 h-4 text-gray-400" />} {topic.isLocked && <FaLock className="w-4 h-4 text-gray-400" />}
{topic.isSolved && <CheckCircle className="w-4 h-4 text-emerald-500" />} {topic.isSolved && <FaCheckCircle className="w-4 h-4 text-emerald-500" />}
<h4 className="text-lg font-semibold text-gray-900 line-clamp-1"> <h4 className="text-lg font-semibold text-gray-900 line-clamp-1">
{topic.title} {topic.title}
</h4> </h4>
@ -396,7 +396,7 @@ export function TopicManagement({
</div> </div>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
<Eye className="w-4 h-4" /> <FaEye className="w-4 h-4" />
<span>{topic.viewCount}</span> <span>{topic.viewCount}</span>
</div> </div>
<span>{topic.replyCount} replies</span> <span>{topic.replyCount} replies</span>
@ -416,9 +416,9 @@ export function TopicManagement({
title={topic.isPinned ? 'Unpin Topic' : 'Pin Topic'} title={topic.isPinned ? 'Unpin Topic' : 'Pin Topic'}
> >
{topic.isPinned ? ( {topic.isPinned ? (
<PinOff className="w-4 h-4" /> <FaThumbtack className="w-4 h-4" />
) : ( ) : (
<Pin className="w-4 h-4" /> <FaTree className="w-4 h-4" />
)} )}
</button> </button>
@ -432,9 +432,9 @@ export function TopicManagement({
title={topic.isLocked ? 'Unlock Topic' : 'Lock Topic'} title={topic.isLocked ? 'Unlock Topic' : 'Lock Topic'}
> >
{topic.isLocked ? ( {topic.isLocked ? (
<Lock className="w-4 h-4" /> <FaLock className="w-4 h-4" />
) : ( ) : (
<Unlock className="w-4 h-4" /> <FaUnlock className="w-4 h-4" />
)} )}
</button> </button>
@ -448,9 +448,9 @@ export function TopicManagement({
title={topic.isSolved ? 'Mark as Unsolved' : 'Mark as Solved'} title={topic.isSolved ? 'Mark as Unsolved' : 'Mark as Solved'}
> >
{topic.isSolved ? ( {topic.isSolved ? (
<CheckCircle className="w-4 h-4" /> <FaCheckCircle className="w-4 h-4" />
) : ( ) : (
<Circle className="w-4 h-4" /> <FaCircle className="w-4 h-4" />
)} )}
</button> </button>
@ -459,7 +459,7 @@ export function TopicManagement({
className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors" className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors"
title={translate('::App.Forum.TopicManagement.EditTopic')} title={translate('::App.Forum.TopicManagement.EditTopic')}
> >
<Edit2 className="w-4 h-4" /> <FaEdit className="w-4 h-4" />
</button> </button>
<button <button
@ -467,7 +467,7 @@ export function TopicManagement({
className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors" className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors"
title={translate('::App.Forum.TopicManagement.DeleteTopic')} title={translate('::App.Forum.TopicManagement.DeleteTopic')}
> >
<Trash2 className="w-4 h-4" /> <FaTrashAlt className="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
@ -501,8 +501,7 @@ export function TopicManagement({
setTopicToDelete(null) setTopicToDelete(null)
} }
}} }}
> ></ConfirmDialog>
</ConfirmDialog>
)} )}
</div> </div>
) )

View file

@ -1,4 +1,4 @@
import { X } from 'lucide-react' import { FaTimes } from 'react-icons/fa';
import { Formik, Form, Field, FieldProps } from 'formik' import { Formik, Form, Field, FieldProps } from 'formik'
import * as Yup from 'yup' import * as Yup from 'yup'
import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor' import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor'
@ -60,7 +60,7 @@ export function CreatePostModal({ onClose, onSubmit, parentPostId }: CreatePostM
: translate('::App.Forum.PostManagement.NewPost')} : translate('::App.Forum.PostManagement.NewPost')}
</h3> </h3>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors"> <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
<X className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>

View file

@ -1,4 +1,4 @@
import { X } from 'lucide-react' import { FaTimes } from 'react-icons/fa';
import { useStoreState } from '@/store/store' import { useStoreState } from '@/store/store'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik' import { Field, FieldProps, Form, Formik } from 'formik'
@ -44,7 +44,7 @@ export function CreateTopicModal({ onClose, onSubmit }: CreateTopicModalProps) {
{translate('::App.Forum.TopicManagement.NewTopic')} {translate('::App.Forum.TopicManagement.NewTopic')}
</h3> </h3>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors"> <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
<X className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>

View file

@ -1,5 +1,4 @@
import React from 'react' import { FaComment, FaLock, FaArrowUp } from 'react-icons/fa';
import { MessageSquare, Lock, TrendingUp } from 'lucide-react'
import { ForumCategory } from '@/proxy/forum/forum' import { ForumCategory } from '@/proxy/forum/forum'
interface CategoryCardProps { interface CategoryCardProps {
@ -35,16 +34,16 @@ export function ForumCategoryCard({ category, onClick }: CategoryCardProps) {
<h3 className="text-lg font-semibold text-gray-900 group-hover:text-blue-600 transition-colors"> <h3 className="text-lg font-semibold text-gray-900 group-hover:text-blue-600 transition-colors">
{category.name} {category.name}
</h3> </h3>
{category.isLocked && <Lock className="w-4 h-4 text-gray-400" />} {category.isLocked && <FaLock className="w-4 h-4 text-gray-400" />}
</div> </div>
<p className="text-gray-600 text-sm mb-3 line-clamp-2">{category.description}</p> <p className="text-gray-600 text-sm mb-3 line-clamp-2">{category.description}</p>
<div className="flex items-center space-x-4 text-sm text-gray-500"> <div className="flex items-center space-x-4 text-sm text-gray-500">
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
<MessageSquare className="w-4 h-4" /> <FaComment className="w-4 h-4" />
<span>{category.topicCount} topics</span> <span>{category.topicCount} topics</span>
</div> </div>
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
<TrendingUp className="w-4 h-4" /> <FaArrowUp className="w-4 h-4" />
<span>{category.postCount} posts</span> <span>{category.postCount} posts</span>
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { Heart, User, CheckCircle, Reply } from 'lucide-react' import { FaHeart, FaCheckCircle, FaReply } from 'react-icons/fa';
import { ForumPost } from '@/proxy/forum/forum' import { ForumPost } from '@/proxy/forum/forum'
import { AVATAR_URL } from '@/constants/app.constant' import { AVATAR_URL } from '@/constants/app.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -56,7 +56,7 @@ export function ForumPostCard({
<h4 className="text-sm font-semibold text-gray-900">{post.authorName}</h4> <h4 className="text-sm font-semibold text-gray-900">{post.authorName}</h4>
{post.isAcceptedAnswer && ( {post.isAcceptedAnswer && (
<div className="flex items-center space-x-1 bg-emerald-100 text-emerald-700 px-2 py-1 rounded-full text-xs"> <div className="flex items-center space-x-1 bg-emerald-100 text-emerald-700 px-2 py-1 rounded-full text-xs">
<CheckCircle className="w-3 h-3" /> <FaCheckCircle className="w-3 h-3" />
<span>{translate('::App.Forum.PostManagement.AcceptedAnswer')}</span> <span>{translate('::App.Forum.PostManagement.AcceptedAnswer')}</span>
</div> </div>
)} )}
@ -80,7 +80,7 @@ export function ForumPostCard({
: 'bg-gray-100 text-gray-600 hover:bg-gray-200' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`} }`}
> >
<Heart className={`w-4 h-4 ${isLiked ? 'fill-current' : ''}`} /> <FaHeart className={`w-4 h-4 ${isLiked ? 'fill-current' : ''}`} />
<span>{post.likeCount}</span> <span>{post.likeCount}</span>
</button> </button>
@ -89,7 +89,7 @@ export function ForumPostCard({
onClick={() => onReply(post.id)} onClick={() => onReply(post.id)}
className="flex items-center space-x-1 px-3 py-1 rounded-full text-sm bg-gray-100 text-gray-600 hover:bg-gray-200 transition-colors" className="flex items-center space-x-1 px-3 py-1 rounded-full text-sm bg-gray-100 text-gray-600 hover:bg-gray-200 transition-colors"
> >
<Reply className="w-4 h-4" /> <FaReply className="w-4 h-4" />
<span>{translate('::App.Forum.PostManagement.PostReply')}</span> <span>{translate('::App.Forum.PostManagement.PostReply')}</span>
</button> </button>
)} )}

View file

@ -1,5 +1,4 @@
import React from 'react' import { FaComment, FaHeart, FaEye, FaThumbtack, FaLock, FaCheckCircle } from 'react-icons/fa';
import { MessageSquare, Heart, Eye, Pin, Lock, CheckCircle } from 'lucide-react'
import { ForumTopic } from '@/proxy/forum/forum' import { ForumTopic } from '@/proxy/forum/forum'
import { AVATAR_URL } from '@/constants/app.constant' import { AVATAR_URL } from '@/constants/app.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -34,9 +33,9 @@ export function ForumTopicCard({ topic, onClick }: TopicCardProps) {
{/* Sol taraf: Başlık, içerik, istatistik */} {/* Sol taraf: Başlık, içerik, istatistik */}
<div className="flex-1 min-w-0 pr-4"> <div className="flex-1 min-w-0 pr-4">
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
{topic.isPinned && <Pin className="w-4 h-4 text-orange-500" />} {topic.isPinned && <FaThumbtack className="w-4 h-4 text-orange-500" />}
{topic.isLocked && <Lock className="w-4 h-4 text-gray-400" />} {topic.isLocked && <FaLock className="w-4 h-4 text-gray-400" />}
{topic.isSolved && <CheckCircle className="w-4 h-4 text-emerald-500" />} {topic.isSolved && <FaCheckCircle className="w-4 h-4 text-emerald-500" />}
<h3 className="text-lg font-semibold text-gray-900 group-hover:text-blue-600 transition-colors line-clamp-1"> <h3 className="text-lg font-semibold text-gray-900 group-hover:text-blue-600 transition-colors line-clamp-1">
{topic.title} {topic.title}
</h3> </h3>
@ -46,15 +45,15 @@ export function ForumTopicCard({ topic, onClick }: TopicCardProps) {
<div className="flex items-center space-x-4 text-sm text-gray-500"> <div className="flex items-center space-x-4 text-sm text-gray-500">
<div className="flex items-center space-x-1" title="Views"> <div className="flex items-center space-x-1" title="Views">
<Eye className="w-4 h-4" /> <FaEye className="w-4 h-4" />
<span>{topic.viewCount}</span> <span>{topic.viewCount}</span>
</div> </div>
<div className="flex items-center space-x-1" title="Replies"> <div className="flex items-center space-x-1" title="Replies">
<MessageSquare className="w-4 h-4" /> <FaComment className="w-4 h-4" />
<span>{topic.replyCount}</span> <span>{topic.replyCount}</span>
</div> </div>
<div className="flex items-center space-x-1" title="Likes"> <div className="flex items-center space-x-1" title="Likes">
<Heart className="w-4 h-4" /> <FaHeart className="w-4 h-4" />
<span>{topic.likeCount}</span> <span>{topic.likeCount}</span>
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { ArrowLeft, Plus, Loader2, Search } from 'lucide-react' import { FaArrowLeft, FaPlus, FaSpinner, FaSearch } from 'react-icons/fa';
import { CreateTopicModal } from './CreateTopicModal' import { CreateTopicModal } from './CreateTopicModal'
import { CreatePostModal } from './CreatePostModal' import { CreatePostModal } from './CreatePostModal'
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
@ -292,7 +292,7 @@ export function ForumView({
return ( return (
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="flex items-center justify-center h-64"> <div className="flex items-center justify-center h-64">
<Loader2 className="w-8 h-8 animate-spin text-blue-600" /> <FaSpinner className="w-8 h-8 animate-spin text-blue-600" />
<span className="ml-2 text-gray-600">Loading forum data...</span> <span className="ml-2 text-gray-600">Loading forum data...</span>
</div> </div>
</div> </div>
@ -311,7 +311,7 @@ export function ForumView({
onClick={handleBack} onClick={handleBack}
className="flex items-center space-x-1 text-blue-600 hover:text-blue-700 transition-colors" className="flex items-center space-x-1 text-blue-600 hover:text-blue-700 transition-colors"
> >
<ArrowLeft className="w-4 h-4" /> <FaArrowLeft className="w-4 h-4" />
<span>Back</span> <span>Back</span>
</button> </button>
)} )}
@ -357,7 +357,7 @@ export function ForumView({
onClick={() => setShowCreateTopic(true)} onClick={() => setShowCreateTopic(true)}
className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors" className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
<span>{translate('::App.Forum.TopicManagement.NewTopic')}</span> <span>{translate('::App.Forum.TopicManagement.NewTopic')}</span>
</button> </button>
)} )}
@ -366,7 +366,7 @@ export function ForumView({
onClick={() => setShowCreatePost(true)} onClick={() => setShowCreatePost(true)}
className="flex items-center space-x-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors" className="flex items-center space-x-2 bg-emerald-600 text-white px-4 py-2 rounded-lg hover:bg-emerald-700 transition-colors"
> >
<Plus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
<span>{translate('::App.Forum.PostManagement.NewPost')}</span> <span>{translate('::App.Forum.PostManagement.NewPost')}</span>
</button> </button>
)} )}
@ -376,7 +376,7 @@ export function ForumView({
onClick={() => setIsSearchModalOpen(true)} onClick={() => setIsSearchModalOpen(true)}
className="hidden md:flex items-center space-x-2 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors" className="hidden md:flex items-center space-x-2 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
> >
<Search className="w-4 h-4 text-gray-400" /> <FaSearch className="w-4 h-4 text-gray-400" />
<span className="text-gray-500">{translate('::App.Forum.TopicManagement.Searchtopics')}</span> <span className="text-gray-500">{translate('::App.Forum.TopicManagement.Searchtopics')}</span>
<kbd className="hidden sm:inline-block px-2 py-1 text-xs font-semibold text-gray-500 bg-gray-100 border border-gray-200 rounded"> <kbd className="hidden sm:inline-block px-2 py-1 text-xs font-semibold text-gray-500 bg-gray-100 border border-gray-200 rounded">
K K
@ -387,7 +387,7 @@ export function ForumView({
onClick={() => setIsSearchModalOpen(true)} onClick={() => setIsSearchModalOpen(true)}
className="md:hidden p-2 text-gray-400 hover:text-gray-600 transition-colors" className="md:hidden p-2 text-gray-400 hover:text-gray-600 transition-colors"
> >
<Search className="w-5 h-5" /> <FaSearch className="w-5 h-5" />
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { X, Search, Folder, MessageSquare, FileText, User } from 'lucide-react' import { FaTimes, FaSearch, FaFolder, FaRegComment, FaFileAlt } from 'react-icons/fa'
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { useForumSearch } from '@/utils/hooks/useForumSearch' import { useForumSearch } from '@/utils/hooks/useForumSearch'
@ -107,7 +107,7 @@ export function SearchModal({
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center pt-20 p-4 z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center pt-20 p-4 z-50">
<div className="bg-white rounded-xl shadow-xl max-w-2xl w-full max-h-[70vh] overflow-hidden"> <div className="bg-white rounded-xl shadow-xl max-w-2xl w-full max-h-[70vh] overflow-hidden">
<div className="flex items-center p-4 border-b border-gray-200"> <div className="flex items-center p-4 border-b border-gray-200">
<Search className="w-5 h-5 text-gray-400 mr-3" /> <FaSearch className="w-5 h-5 text-gray-400 mr-3" />
<input <input
type="text" type="text"
value={searchQuery} value={searchQuery}
@ -121,14 +121,14 @@ export function SearchModal({
onClick={onClose} onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors ml-3" className="text-gray-400 hover:text-gray-600 transition-colors ml-3"
> >
<X className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
<div className="overflow-y-auto max-h-96"> <div className="overflow-y-auto max-h-96">
{!searchQuery.trim() ? ( {!searchQuery.trim() ? (
<div className="p-8 text-center text-gray-500"> <div className="p-8 text-center text-gray-500">
<Search className="w-12 h-12 mx-auto mb-4 text-gray-300" /> <FaSearch className="w-12 h-12 mx-auto mb-4 text-gray-300" />
<p>Start typing to search categories, topics, and posts...</p> <p>Start typing to search categories, topics, and posts...</p>
</div> </div>
) : !hasResults ? ( ) : !hasResults ? (
@ -157,7 +157,7 @@ export function SearchModal({
<div className="flex items-center space-x-3 flex-1"> <div className="flex items-center space-x-3 flex-1">
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<div className="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center"> <div className="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center">
<Folder className="w-4 h-4 text-blue-600" /> <FaFolder className="w-4 h-4 text-blue-600" />
</div> </div>
</div> </div>
<div className="text-left"> <div className="text-left">
@ -197,7 +197,7 @@ export function SearchModal({
<div className="flex items-center space-x-3 flex-1"> <div className="flex items-center space-x-3 flex-1">
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<div className="w-8 h-8 bg-emerald-100 rounded-lg flex items-center justify-center"> <div className="w-8 h-8 bg-emerald-100 rounded-lg flex items-center justify-center">
<MessageSquare className="w-4 h-4 text-emerald-600" /> <FaRegComment className="w-4 h-4 text-emerald-600" />
</div> </div>
</div> </div>
<div className="text-left"> <div className="text-left">
@ -241,7 +241,7 @@ export function SearchModal({
<div className="flex items-center space-x-3 flex-1"> <div className="flex items-center space-x-3 flex-1">
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<div className="w-8 h-8 bg-orange-100 rounded-lg flex items-center justify-center"> <div className="w-8 h-8 bg-orange-100 rounded-lg flex items-center justify-center">
<FileText className="w-4 h-4 text-orange-600" /> <FaFileAlt className="w-4 h-4 text-orange-600" />
</div> </div>
</div> </div>
<div className="text-left"> <div className="text-left">

View file

@ -20,7 +20,11 @@ import {
import { Field, FieldProps, Form, Formik } from 'formik' import { Field, FieldProps, Form, Formik } from 'formik'
import { SelectBoxOption } from '@/shared/types' import { SelectBoxOption } from '@/shared/types'
import * as Yup from 'yup' import * as Yup from 'yup'
import { ExternalLink, FileText, Plus, Trash2 } from 'lucide-react' import {
FaExternalLinkAlt,
FaPlus,
FaTrashAlt
} from 'react-icons/fa';
import { MenuDto } from '@/proxy/menus/models' import { MenuDto } from '@/proxy/menus/models'
interface MenuItemComponentProps { interface MenuItemComponentProps {
@ -43,7 +47,7 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
permissions, permissions,
}) => { }) => {
const { translate } = useLocalization() const { translate } = useLocalization()
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: item.id || '', id: item.id || '',
data: { data: {
@ -124,17 +128,21 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
{isDesignMode && ( {isDesignMode && (
<div className="flex gap-2 items-center mr-2"> <div className="flex gap-2 items-center mr-2">
<button onClick={() => setIsModalOpen(true)} title="New Item"> <button onClick={() => setIsModalOpen(true)} title="New Item">
<Plus size={16} className="text-green-600 hover:text-green-800" /> <FaPlus size={16} className="text-green-600 hover:text-green-800" />
</button> </button>
<button onClick={handleDelete} title="Delete Item"> <button onClick={handleDelete} title="Delete Item">
<Trash2 size={16} className="text-red-600 hover:text-red-800" /> <FaTrashAlt size={16} className="text-red-600 hover:text-red-800" />
</button> </button>
</div> </div>
)} )}
<div className="flex items-center gap-3 flex-1 min-w-0"> <div className="flex items-center gap-3 flex-1 min-w-0">
<div className="flex-shrink-0 text-gray-600 text-xl"> <div className="flex-shrink-0 text-gray-600 text-xl">
{navigationIcon[item.icon || ''] ?? <FaQuestionCircle className="text-gray-400" />} {navigationIcon[item.icon || ''] ? (
React.createElement(navigationIcon[item.icon || ''], { className: 'text-gray-400' })
) : (
<FaQuestionCircle className="text-gray-400" />
)}
</div> </div>
<span <span
@ -146,7 +154,7 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
{translate('::' + item.displayName)} {translate('::' + item.displayName)}
</span> </span>
{item.url && <ExternalLink size={12} className="flex-shrink-0 text-gray-400" />} {item.url && <FaExternalLinkAlt size={12} className="flex-shrink-0 text-gray-400" />}
</div> </div>
<div className="flex items-center gap-2 flex-shrink-0"> <div className="flex items-center gap-2 flex-shrink-0">

View file

@ -2,7 +2,12 @@ import React, { useState } from 'react'
import { SortableMenuTree } from './SortableMenuTree' import { SortableMenuTree } from './SortableMenuTree'
import { MenuItem } from '@/@types/menu' import { MenuItem } from '@/@types/menu'
import { useMenuData } from '@/utils/hooks/useMenuData' import { useMenuData } from '@/utils/hooks/useMenuData'
import { AlertCircle, Loader2, Menu, Save } from 'lucide-react' import {
FaRegBell,
FaSpinner,
FaBars,
FaRegSave
} from 'react-icons/fa';
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -53,7 +58,7 @@ export const MenuManager = () => {
return ( return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center"> <div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="flex items-center gap-3 text-gray-600"> <div className="flex items-center gap-3 text-gray-600">
<Loader2 size={24} className="animate-spin" /> <FaSpinner className="animate-spin" />
<span className="text-lg">Loading menu configuration...</span> <span className="text-lg">Loading menu configuration...</span>
</div> </div>
</div> </div>
@ -65,7 +70,7 @@ export const MenuManager = () => {
<div className="min-h-screen bg-gray-50 flex items-center justify-center"> <div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="bg-white p-8 rounded-lg shadow-md max-w-md w-full mx-4"> <div className="bg-white p-8 rounded-lg shadow-md max-w-md w-full mx-4">
<div className="flex items-center gap-3 text-red-600 mb-4"> <div className="flex items-center gap-3 text-red-600 mb-4">
<AlertCircle size={24} /> <FaRegBell size={24} />
<h2 className="text-lg font-semibold">Error Loading Menu</h2> <h2 className="text-lg font-semibold">Error Loading Menu</h2>
</div> </div>
<p className="text-gray-600 mb-6">{error}</p> <p className="text-gray-600 mb-6">{error}</p>
@ -92,7 +97,7 @@ export const MenuManager = () => {
<div className="flex items-center justify-between mb-6 flex-wrap gap-4"> <div className="flex items-center justify-between mb-6 flex-wrap gap-4">
{/* Sol kısım: Başlık */} {/* Sol kısım: Başlık */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Menu size={20} className="text-gray-600" /> <FaBars size={20} className="text-gray-600" />
<h2 className="text-lg font-semibold text-gray-900">Menu Manager</h2> <h2 className="text-lg font-semibold text-gray-900">Menu Manager</h2>
<span className="text-sm text-gray-500">({menuItems.length} root items)</span> <span className="text-sm text-gray-500">({menuItems.length} root items)</span>
</div> </div>
@ -133,12 +138,12 @@ export const MenuManager = () => {
> >
{isSaving ? ( {isSaving ? (
<> <>
<Loader2 size={16} className="animate-spin" /> <FaSpinner size={16} className="animate-spin" />
Saving... Saving...
</> </>
) : ( ) : (
<> <>
<Save size={16} /> <FaRegSave size={16} />
Save Changes Save Changes
</> </>
)} )}
@ -156,7 +161,7 @@ export const MenuManager = () => {
/> />
) : ( ) : (
<div className="text-center py-12 text-gray-500"> <div className="text-center py-12 text-gray-500">
<Menu size={24} className="mx-auto mb-4 text-gray-300" /> <FaBars size={24} className="mx-auto mb-4 text-gray-300" />
<p className="text-lg">No menu items found</p> <p className="text-lg">No menu items found</p>
<p className="text-sm">Try refreshing the page or contact your administrator</p> <p className="text-sm">Try refreshing the page or contact your administrator</p>
</div> </div>

View file

@ -1,5 +1,10 @@
import React from 'react' import React from 'react'
import { Users, Award, Clock, Globe2 } from 'lucide-react' import {
FaUsers,
FaAward,
FaClock,
FaGlobe
} from 'react-icons/fa';
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { useCountUp } from '@/utils/hooks/useCountUp' import { useCountUp } from '@/utils/hooks/useCountUp'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
@ -45,26 +50,26 @@ const About: React.FC = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8"> <div className="grid grid-cols-1 md:grid-cols-4 gap-8">
<div className="text-center" ref={clientsCount.elementRef}> <div className="text-center" ref={clientsCount.elementRef}>
<Users className="w-12 h-12 text-blue-600 mx-auto mb-4" /> <FaUsers className="w-12 h-12 text-blue-600 mx-auto mb-4" />
<div className="text-4xl font-bold text-gray-900 mb-2"> <div className="text-4xl font-bold text-gray-900 mb-2">
{clientsCount.displayValue} {clientsCount.displayValue}
</div> </div>
<div className="text-gray-600">{translate('::Public.about.stats.clients')}</div> <div className="text-gray-600">{translate('::Public.about.stats.clients')}</div>
</div> </div>
<div className="text-center" ref={experienceCount.elementRef}> <div className="text-center" ref={experienceCount.elementRef}>
<Award className="w-12 h-12 text-blue-600 mx-auto mb-4" /> <FaAward className="w-12 h-12 text-blue-600 mx-auto mb-4" />
<div className="text-4xl font-bold text-gray-900 mb-2"> <div className="text-4xl font-bold text-gray-900 mb-2">
{experienceCount.displayValue} {experienceCount.displayValue}
</div> </div>
<div className="text-gray-600">{translate('::Public.about.stats.experience')}</div> <div className="text-gray-600">{translate('::Public.about.stats.experience')}</div>
</div> </div>
<div className="text-center"> <div className="text-center">
<Clock className="w-12 h-12 text-blue-600 mx-auto mb-4" /> <FaClock className="w-12 h-12 text-blue-600 mx-auto mb-4" />
<div className="text-4xl font-bold text-gray-900 mb-2">7/24</div> <div className="text-4xl font-bold text-gray-900 mb-2">7/24</div>
<div className="text-gray-600">{translate('::Public.about.stats.support')}</div> <div className="text-gray-600">{translate('::Public.about.stats.support')}</div>
</div> </div>
<div className="text-center" ref={countriesCount.elementRef}> <div className="text-center" ref={countriesCount.elementRef}>
<Globe2 className="w-12 h-12 text-blue-600 mx-auto mb-4" /> <FaGlobe className="w-12 h-12 text-blue-600 mx-auto mb-4" />
<div className="text-4xl font-bold text-gray-900 mb-2"> <div className="text-4xl font-bold text-gray-900 mb-2">
{countriesCount.displayValue} {countriesCount.displayValue}
</div> </div>

View file

@ -1,6 +1,11 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { Calendar, Clock, User, Tag, Search } from 'lucide-react' import {
FaCalendarAlt,
FaUser,
FaTag,
FaSearch
} from 'react-icons/fa';
import dayjs from 'dayjs' import dayjs from 'dayjs'
import 'dayjs/locale/tr' import 'dayjs/locale/tr'
import { BlogCategory, BlogPost } from '@/proxy/blog/blog' import { BlogCategory, BlogPost } from '@/proxy/blog/blog'
@ -110,7 +115,7 @@ const Blog = () => {
placeholder="Blog yazılarında ara..." placeholder="Blog yazılarında ara..."
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/> />
<Search className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" /> <FaSearch className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" />
</div> </div>
</form> </form>
@ -181,7 +186,7 @@ const Blog = () => {
key={index} key={index}
className="inline-flex items-center text-xs bg-gray-100 text-gray-600 px-2 py-1 rounded" className="inline-flex items-center text-xs bg-gray-100 text-gray-600 px-2 py-1 rounded"
> >
<Tag className="w-3 h-3 mr-1" /> <FaTag className="w-3 h-3 mr-1" />
{tag} {tag}
</span> </span>
))} ))}
@ -190,11 +195,11 @@ const Blog = () => {
<div className="flex items-center text-sm text-gray-500 space-x-4"> <div className="flex items-center text-sm text-gray-500 space-x-4">
<div className="flex items-center"> <div className="flex items-center">
<User size={16} className="mr-1" /> <FaUser size={16} className="mr-1" />
{post.author.name} {post.author.name}
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<Calendar size={16} className="mr-1" /> <FaCalendarAlt size={16} className="mr-1" />
{dayjs(post.publishedAt || post.creationTime).format('DD MMM YYYY')} {dayjs(post.publishedAt || post.creationTime).format('DD MMM YYYY')}
</div> </div>
</div> </div>

View file

@ -1,14 +1,14 @@
import React from 'react' import React from 'react'
import { import {
Mail, FaMailBulk,
Phone, FaPhone,
MapPin, FaMapPin,
FileText, FaFileAlt,
Building, FaBuilding,
CalendarDays, FaCalendarAlt,
CalendarCheck, FaCalendarCheck,
MessageCircle, FaRegComment
} from 'lucide-react' } from 'react-icons/fa';
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
@ -53,19 +53,19 @@ const Contact: React.FC = () => {
</h2> </h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-start space-x-4"> <div className="flex items-start space-x-4">
<MapPin className="w-6 h-6 text-blue-600 flex-shrink-0 mt-1" /> <FaMapPin className="w-6 h-6 text-blue-600 flex-shrink-0 mt-1" />
<div> <div>
<p className="text-gray-600">{translate('::Public.contact.address.full')}</p> <p className="text-gray-600">{translate('::Public.contact.address.full')}</p>
</div> </div>
</div> </div>
<div className="flex items-start space-x-4"> <div className="flex items-start space-x-4">
<Phone className="w-6 h-6 text-blue-600 flex-shrink-0" /> <FaPhone className="w-6 h-6 text-blue-600 flex-shrink-0" />
<div> <div>
<p className="text-gray-600">+90 (544) 769 7 638</p> <p className="text-gray-600">+90 (544) 769 7 638</p>
</div> </div>
</div> </div>
<div className="flex items-start space-x-4"> <div className="flex items-start space-x-4">
<Mail className="w-6 h-6 text-blue-600 flex-shrink-0" /> <FaMailBulk className="w-6 h-6 text-blue-600 flex-shrink-0" />
<div> <div>
<p className="text-gray-600"> <p className="text-gray-600">
<a <a
@ -78,13 +78,13 @@ const Contact: React.FC = () => {
</div> </div>
</div> </div>
<div className="flex items-start space-x-4"> <div className="flex items-start space-x-4">
<Building className="w-6 h-6 text-blue-600 flex-shrink-0" /> <FaBuilding className="w-6 h-6 text-blue-600 flex-shrink-0" />
<div> <div>
<p className="text-gray-600">Kozyatağı</p> <p className="text-gray-600">Kozyatağı</p>
</div> </div>
</div> </div>
<div className="flex items-start space-x-4"> <div className="flex items-start space-x-4">
<FileText className="w-6 h-6 text-blue-600 flex-shrink-0" /> <FaFileAlt className="w-6 h-6 text-blue-600 flex-shrink-0" />
<div> <div>
<p className="text-gray-600">32374982750</p> <p className="text-gray-600">32374982750</p>
</div> </div>
@ -124,19 +124,19 @@ const Contact: React.FC = () => {
<div className="flex items-start space-x-4"> <div className="flex items-start space-x-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<CalendarDays className="w-5 h-5 text-blue-500" /> <FaCalendarAlt className="w-5 h-5 text-blue-500" />
<p className="text-gray-600"> <p className="text-gray-600">
{translate('::Public.contact.workHours.weekday')} {translate('::Public.contact.workHours.weekday')}
</p> </p>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<CalendarCheck className="w-5 h-5 text-blue-500" /> <FaCalendarCheck className="w-5 h-5 text-blue-500" />
<p className="text-gray-600"> <p className="text-gray-600">
{translate('::Public.contact.workHours.weekend')} {translate('::Public.contact.workHours.weekend')}
</p> </p>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<MessageCircle className="w-5 h-5 text-green-500" /> <FaRegComment className="w-5 h-5 text-green-500" />
<p className="text-gray-600"> <p className="text-gray-600">
{translate('::Public.contact.workHours.whatsapp')} {translate('::Public.contact.workHours.whatsapp')}
</p> </p>

View file

@ -1,15 +1,15 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
Building2, FaBuilding,
User, FaUser,
Mail, FaEnvelope,
Phone, FaPhone,
MapPin, FaMapPin,
Users, FaUsers,
MessageSquare, FaRegComment,
Send, FaPaperPlane,
CheckCircle, FaCheckCircle
} from "lucide-react"; } from 'react-icons/fa';
import { useLocalization } from "@/utils/hooks/useLocalization"; import { useLocalization } from "@/utils/hooks/useLocalization";
interface DemoModalProps { interface DemoModalProps {
@ -131,7 +131,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
</button> </button>
<div className="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-6"> <div className="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-6">
<CheckCircle className="w-8 h-8 text-white" /> <FaCheckCircle className="w-8 h-8 text-white" />
</div> </div>
<h2 className="text-2xl font-bold text-gray-800 mb-4"> <h2 className="text-2xl font-bold text-gray-800 mb-4">
Teşekkürler! Teşekkürler!
@ -189,7 +189,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.company')} * {translate('::Public.common.company')} *
</label> </label>
<div className="relative"> <div className="relative">
<Building2 className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaBuilding className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="text" type="text"
autoFocus autoFocus
@ -212,7 +212,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.fullName')} * {translate('::Public.common.fullName')} *
</label> </label>
<div className="relative"> <div className="relative">
<User className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaUser className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="text" type="text"
name="fullName" name="fullName"
@ -235,7 +235,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.email')} * {translate('::Public.common.email')} *
</label> </label>
<div className="relative"> <div className="relative">
<Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaEnvelope className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="email" type="email"
name="email" name="email"
@ -256,7 +256,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.phone')} * {translate('::Public.common.phone')} *
</label> </label>
<div className="relative"> <div className="relative">
<Phone className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaPhone className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="tel" type="tel"
name="phone" name="phone"
@ -279,7 +279,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.address')} * {translate('::Public.common.address')} *
</label> </label>
<div className="relative"> <div className="relative">
<MapPin className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaMapPin className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="text" type="text"
name="address" name="address"
@ -302,7 +302,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.branchCount')} * {translate('::Public.common.branchCount')} *
</label> </label>
<div className="relative"> <div className="relative">
<Building2 className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaBuilding className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="number" type="number"
name="numberOfBranches" name="numberOfBranches"
@ -324,7 +324,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.userCount')} * {translate('::Public.common.userCount')} *
</label> </label>
<div className="relative"> <div className="relative">
<Users className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaUsers className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
type="number" type="number"
name="numberOfUsers" name="numberOfUsers"
@ -348,7 +348,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
{translate('::Public.common.message')} * {translate('::Public.common.message')} *
</label> </label>
<div className="relative"> <div className="relative">
<MessageSquare className="absolute left-3 top-3 w-5 h-5 text-gray-400" /> <FaRegComment className="absolute left-3 top-3 w-5 h-5 text-gray-400" />
<textarea <textarea
name="message" name="message"
value={formData.message} value={formData.message}
@ -369,7 +369,7 @@ const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
type="submit" type="submit"
className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-300 transform hover:scale-[1.02] hover:shadow-lg flex items-center justify-center gap-2" className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-300 transform hover:scale-[1.02] hover:shadow-lg flex items-center justify-center gap-2"
> >
<Send className="w-5 h-5" /> <FaPaperPlane className="w-5 h-5" />
{translate('::Public.demo.send')} {translate('::Public.demo.send')}
</button> </button>
</div> </div>

View file

@ -1,20 +1,20 @@
import React from 'react' import React from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { import {
ArrowRight, FaArrowRight,
Calendar, FaCalendarAlt,
Users, FaUsers,
Shield, FaShieldAlt,
Monitor, FaDesktop,
Smartphone, FaMobileAlt,
Server, FaServer,
Database, FaDatabase,
BarChart, FaChartBar,
BookOpen, FaBookOpen,
CreditCard, FaCreditCard,
MessageSquare, FaRegComment,
Phone, FaPhone
} from 'lucide-react' } from 'react-icons/fa';
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
@ -24,42 +24,42 @@ const Home: React.FC = () => {
const features = [ const features = [
{ {
icon: <Users className="w-12 h-12 text-blue-500" />, icon: <FaUsers className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.reliable'), title: translate('::Public.features.reliable'),
description: translate('::Public.features.reliable.desc'), description: translate('::Public.features.reliable.desc'),
}, },
{ {
icon: <Calendar className="w-12 h-12 text-blue-500" />, icon: <FaCalendarAlt className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.rapid'), title: translate('::Public.features.rapid'),
description: translate('::Public.features.rapid.desc'), description: translate('::Public.features.rapid.desc'),
}, },
{ {
icon: <BookOpen className="w-12 h-12 text-blue-500" />, icon: <FaBookOpen className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.expert'), title: translate('::Public.features.expert'),
description: translate('::Public.features.expert.desc'), description: translate('::Public.features.expert.desc'),
}, },
{ {
icon: <CreditCard className="w-12 h-12 text-blue-500" />, icon: <FaCreditCard className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.muhasebe'), title: translate('::Public.features.muhasebe'),
description: translate('::Public.features.muhasebe.desc'), description: translate('::Public.features.muhasebe.desc'),
}, },
{ {
icon: <MessageSquare className="w-12 h-12 text-blue-500" />, icon: <FaRegComment className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.iletisim'), title: translate('::Public.features.iletisim'),
description: translate('::Public.features.iletisim.desc'), description: translate('::Public.features.iletisim.desc'),
}, },
{ {
icon: <Phone className="w-12 h-12 text-blue-500" />, icon: <FaPhone className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.mobil'), title: translate('::Public.features.mobil'),
description: translate('::Public.features.mobil.desc'), description: translate('::Public.features.mobil.desc'),
}, },
{ {
icon: <BarChart className="w-12 h-12 text-blue-500" />, icon: <FaChartBar className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.scalable'), title: translate('::Public.features.scalable'),
description: translate('::Public.features.scalable.desc'), description: translate('::Public.features.scalable.desc'),
}, },
{ {
icon: <Shield className="w-12 h-12 text-blue-500" />, icon: <FaShieldAlt className="w-12 h-12 text-blue-500" />,
title: translate('::Public.features.guvenlik'), title: translate('::Public.features.guvenlik'),
description: translate('::Public.features.guvenlik.desc'), description: translate('::Public.features.guvenlik.desc'),
}, },
@ -67,25 +67,25 @@ const Home: React.FC = () => {
const solutions = [ const solutions = [
{ {
icon: <Monitor className="w-16 h-16 text-white" />, icon: <FaDesktop className="w-16 h-16 text-white" />,
title: translate('::Public.solutions.web.title'), title: translate('::Public.solutions.web.title'),
description: translate('::Public.solutions.web.desc'), description: translate('::Public.solutions.web.desc'),
color: 'bg-blue-600', color: 'bg-blue-600',
}, },
{ {
icon: <Smartphone className="w-16 h-16 text-white" />, icon: <FaMobileAlt className="w-16 h-16 text-white" />,
title: translate('::Public.solutions.mobile.title'), title: translate('::Public.solutions.mobile.title'),
description: translate('::Public.solutions.mobile.desc'), description: translate('::Public.solutions.mobile.desc'),
color: 'bg-purple-600', color: 'bg-purple-600',
}, },
{ {
icon: <Server className="w-16 h-16 text-white" />, icon: <FaServer className="w-16 h-16 text-white" />,
title: translate('::Public.solutions.custom.title'), title: translate('::Public.solutions.custom.title'),
description: translate('::Public.solutions.custom.desc'), description: translate('::Public.solutions.custom.desc'),
color: 'bg-green-600', color: 'bg-green-600',
}, },
{ {
icon: <Database className="w-16 h-16 text-white" />, icon: <FaDatabase className="w-16 h-16 text-white" />,
title: translate('::Public.solutions.database.title'), title: translate('::Public.solutions.database.title'),
description: translate('::Public.solutions.database.desc'), description: translate('::Public.solutions.database.desc'),
color: 'bg-red-600', color: 'bg-red-600',
@ -128,7 +128,7 @@ const Home: React.FC = () => {
className="inline-flex items-center justify-center px-8 py-4 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white rounded-lg font-semibold transition-all transform hover:scale-105" className="inline-flex items-center justify-center px-8 py-4 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white rounded-lg font-semibold transition-all transform hover:scale-105"
> >
{translate('::Public.hero.cta.consultation')}{' '} {translate('::Public.hero.cta.consultation')}{' '}
<ArrowRight className="ml-2" size={20} /> <FaArrowRight className="ml-2" size={20} />
</Link> </Link>
<Link <Link
to={ROUTES_ENUM.public.products} to={ROUTES_ENUM.public.products}
@ -140,21 +140,21 @@ const Home: React.FC = () => {
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-4xl mx-auto"> <div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-4xl mx-auto">
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all"> <div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all">
<Calendar className="mx-auto mb-4 text-blue-400" size={40} /> <FaCalendarAlt className="mx-auto mb-4 text-blue-400" size={40} />
<h3 className="text-xl font-semibold mb-3 text-white"> <h3 className="text-xl font-semibold mb-3 text-white">
{translate('::Public.hero.service1.title')} {translate('::Public.hero.service1.title')}
</h3> </h3>
<p className="text-gray-300">{translate('::Public.hero.service1.desc')}</p> <p className="text-gray-300">{translate('::Public.hero.service1.desc')}</p>
</div> </div>
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all"> <div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all">
<Users className="mx-auto mb-4 text-purple-400" size={40} /> <FaUsers className="mx-auto mb-4 text-purple-400" size={40} />
<h3 className="text-xl font-semibold mb-3 text-white"> <h3 className="text-xl font-semibold mb-3 text-white">
{translate('::Public.hero.service2.title')} {translate('::Public.hero.service2.title')}
</h3> </h3>
<p className="text-gray-300">{translate('::Public.hero.service2.desc')}</p> <p className="text-gray-300">{translate('::Public.hero.service2.desc')}</p>
</div> </div>
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all"> <div className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all">
<Shield className="mx-auto mb-4 text-indigo-400" size={40} /> <FaShieldAlt className="mx-auto mb-4 text-indigo-400" size={40} />
<h3 className="text-xl font-semibold mb-3 text-white"> <h3 className="text-xl font-semibold mb-3 text-white">
{translate('::Public.hero.service3.title')} {translate('::Public.hero.service3.title')}
</h3> </h3>

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Frown } from 'lucide-react'; // Lucide-react kütüphanesinden Frown ikonunu import et import { FaFrown } from 'react-icons/fa';
import { ROUTES_ENUM } from '@/routes/route.constant'; import { ROUTES_ENUM } from '@/routes/route.constant';
import { useLocalization } from '@/utils/hooks/useLocalization'; import { useLocalization } from '@/utils/hooks/useLocalization';
@ -8,7 +8,7 @@ const NotFound: React.FC = () => {
return ( return (
<div className="flex flex-col items-center justify-center min-h-screen bg-white text-gray-700 p-4"> {/* Arka plan ve metin rengi güncellendi, padding eklendi */} <div className="flex flex-col items-center justify-center min-h-screen bg-white text-gray-700 p-4"> {/* Arka plan ve metin rengi güncellendi, padding eklendi */}
<Frown size={128} className="text-blue-600 mb-6" /> {/* İkon boyutu ve rengi güncellendi */} <FaFrown size={128} className="text-blue-600 mb-6" /> {/* İkon boyutu ve rengi güncellendi */}
<h1 className="text-7xl font-bold text-gray-900 mb-4">404</h1> {/* Başlık boyutu ve rengi güncellendi */} <h1 className="text-7xl font-bold text-gray-900 mb-4">404</h1> {/* Başlık boyutu ve rengi güncellendi */}
<p className="text-xl text-gray-600 mb-8 text-center max-w-md"> {/* Metin rengi, margin ve max-width güncellendi */} <p className="text-xl text-gray-600 mb-8 text-center max-w-md"> {/* Metin rengi, margin ve max-width güncellendi */}
{translate('::Public.notFound.message')} {translate('::Public.notFound.message')}

View file

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { Code2, Globe2, Server, Users, Shield, Settings, CheckCircle } from 'lucide-react' import { FaCode, FaGlobe, FaServer, FaUsers, FaShieldAlt, FaCog, FaCheckCircle } from 'react-icons/fa';
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
@ -10,7 +10,7 @@ const Services: React.FC = () => {
const services = [ const services = [
{ {
icon: <Code2 className="w-12 h-12 text-blue-600" />, icon: <FaCode className="w-12 h-12 text-blue-600" />,
title: translate('::Public.services.software.title'), title: translate('::Public.services.software.title'),
description: translate('::Public.services.software.desc'), description: translate('::Public.services.software.desc'),
features: [ features: [
@ -22,7 +22,7 @@ const Services: React.FC = () => {
], ],
}, },
{ {
icon: <Users className="w-12 h-12 text-purple-600" />, icon: <FaUsers className="w-12 h-12 text-purple-600" />,
title: translate('::Public.services.web.title'), title: translate('::Public.services.web.title'),
description: translate('::Public.services.web.desc'), description: translate('::Public.services.web.desc'),
features: [ features: [
@ -34,7 +34,7 @@ const Services: React.FC = () => {
], ],
}, },
{ {
icon: <Shield className="w-12 h-12 text-green-600" />, icon: <FaShieldAlt className="w-12 h-12 text-green-600" />,
title: translate('::Public.services.mobile.title'), title: translate('::Public.services.mobile.title'),
description: translate('::Public.services.mobile.desc'), description: translate('::Public.services.mobile.desc'),
features: [ features: [
@ -46,7 +46,7 @@ const Services: React.FC = () => {
], ],
}, },
{ {
icon: <Server className="w-12 h-12 text-red-600" />, icon: <FaServer className="w-12 h-12 text-red-600" />,
title: translate('::Public.services.database.title'), title: translate('::Public.services.database.title'),
description: translate('::Public.services.database.desc'), description: translate('::Public.services.database.desc'),
features: [ features: [
@ -58,7 +58,7 @@ const Services: React.FC = () => {
], ],
}, },
{ {
icon: <Globe2 className="w-12 h-12 text-yellow-600" />, icon: <FaGlobe className="w-12 h-12 text-yellow-600" />,
title: translate('::Public.services.integration.title'), title: translate('::Public.services.integration.title'),
description: translate('::Public.services.integration.desc'), description: translate('::Public.services.integration.desc'),
features: [ features: [
@ -70,7 +70,7 @@ const Services: React.FC = () => {
], ],
}, },
{ {
icon: <Settings className="w-12 h-12 text-indigo-600" />, icon: <FaCog className="w-12 h-12 text-indigo-600" />,
title: translate('::Public.services.consulting.title'), title: translate('::Public.services.consulting.title'),
description: translate('::Public.services.consulting.desc'), description: translate('::Public.services.consulting.desc'),
features: [ features: [
@ -189,7 +189,7 @@ const Services: React.FC = () => {
<ul className="space-y-3 mb-8"> <ul className="space-y-3 mb-8">
{plan.features.map((feature, fIndex) => ( {plan.features.map((feature, fIndex) => (
<li key={fIndex} className="flex items-center space-x-2 text-gray-700"> <li key={fIndex} className="flex items-center space-x-2 text-gray-700">
<CheckCircle className="w-5 h-5 text-green-500 flex-shrink-0" /> <FaCheckCircle className="w-5 h-5 text-green-500 flex-shrink-0" />
<span>{feature}</span> <span>{feature}</span>
</li> </li>
))} ))}