diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3daffd2..0000000 --- a/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -# Multi-stage build for Laravel with React frontend -FROM node:22-alpine AS frontend-builder - -WORKDIR /app -COPY package*.json ./ -RUN npm install --only=production -COPY . . -RUN npm run build - -FROM php:8.4-fpm-alpine - -# Install system dependencies and PHP extensions -RUN apk add --no-cache \ - git \ - curl \ - libpng-dev \ - oniguruma-dev \ - libxml2-dev \ - zip \ - unzip \ - autoconf \ - gcc \ - g++ \ - make \ - gettext \ - && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd \ - && pecl install redis \ - && docker-php-ext-enable redis - -# Install Composer -COPY --from=composer:latest /usr/bin/composer /usr/bin/composer - -# Set working directory -WORKDIR /var/www/html - -# Copy composer files -COPY composer*.json ./ - -# Copy application files (needed for artisan in composer scripts) -COPY . . - -# Install dependencies -RUN composer install --no-dev --optimize-autoloader --no-interaction --ignore-platform-reqs - -# Copy production environment file and generate APP_KEY -COPY docker/build/laravel.env .env -RUN php artisan key:generate - -# Copy built frontend assets -COPY --from=frontend-builder /app/public/build /var/www/html/public/build - -# Set permissions -RUN chown -R www-data:www-data /var/www/html \ - && chmod -R 755 /var/www/html/storage \ - && chmod -R 755 /var/www/html/bootstrap/cache - -# Create entrypoint script and health check scripts -COPY docker/build/entrypoint.sh /entrypoint.sh -COPY docker/build/wait-for-db.php /docker/wait-for-db.php -COPY docker/build/wait-for-redis.php /docker/wait-for-redis.php -RUN chmod +x /entrypoint.sh /docker/wait-for-db.php /docker/wait-for-redis.php - -EXPOSE 8000 - -ENTRYPOINT ["/entrypoint.sh"] -CMD ["web"] diff --git a/.env.example b/backend/.env.example similarity index 100% rename from .env.example rename to backend/.env.example diff --git a/components.json b/components.json deleted file mode 100644 index 14024c7..0000000 --- a/components.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "resources/css/app.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "iconLibrary": "lucide" -} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 34b7daf..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,73 +0,0 @@ -services: - laravel.test: - build: - context: ./vendor/laravel/sail/runtimes/8.4 - dockerfile: Dockerfile - args: - WWWGROUP: '${WWWGROUP}' - image: sail-8.4/app - extra_hosts: - - 'host.docker.internal:host-gateway' - ports: - - '${APP_PORT:-80}:80' - - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' - environment: - WWWUSER: '${WWWUSER}' - LARAVEL_SAIL: 1 - XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' - XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' - IGNITION_LOCAL_SITES_PATH: '${PWD}' - volumes: - - '.:/var/www/html' - networks: - - sail - depends_on: - - mysql - - redis - mysql: - image: 'mysql/mysql-server:8.0' - ports: - - '${FORWARD_DB_PORT:-3306}:3306' - environment: - MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' - MYSQL_ROOT_HOST: '%' - MYSQL_DATABASE: '${DB_DATABASE}' - MYSQL_USER: '${DB_USERNAME}' - MYSQL_PASSWORD: '${DB_PASSWORD}' - MYSQL_ALLOW_EMPTY_PASSWORD: 1 - volumes: - - 'sail-mysql:/var/lib/mysql' - - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' - networks: - - sail - healthcheck: - test: - - CMD - - mysqladmin - - ping - - '-p${DB_PASSWORD}' - retries: 3 - timeout: 5s - redis: - image: 'redis:alpine' - ports: - - '${FORWARD_REDIS_PORT:-6379}:6379' - volumes: - - 'sail-redis:/data' - networks: - - sail - healthcheck: - test: - - CMD - - redis-cli - - ping - retries: 3 - timeout: 5s -networks: - sail: - driver: bridge -volumes: - sail-mysql: - driver: local - sail-redis: - driver: local diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index a136d22..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,44 +0,0 @@ -import js from '@eslint/js'; -import prettier from 'eslint-config-prettier'; -import react from 'eslint-plugin-react'; -import reactHooks from 'eslint-plugin-react-hooks'; -import globals from 'globals'; -import typescript from 'typescript-eslint'; - -/** @type {import('eslint').Linter.Config[]} */ -export default [ - js.configs.recommended, - ...typescript.configs.recommended, - { - ...react.configs.flat.recommended, - ...react.configs.flat['jsx-runtime'], // Required for React 17+ - languageOptions: { - globals: { - ...globals.browser, - }, - }, - rules: { - 'react/react-in-jsx-scope': 'off', - 'react/prop-types': 'off', - 'react/no-unescaped-entities': 'off', - }, - settings: { - react: { - version: 'detect', - }, - }, - }, - { - plugins: { - 'react-hooks': reactHooks, - }, - rules: { - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', - }, - }, - { - ignores: ['vendor', 'node_modules', 'public', 'bootstrap/ssr', 'tailwind.config.js'], - }, - prettier, // Turn off all rules that might conflict with Prettier -]; diff --git a/.prettierignore b/frontend/.prettierignore similarity index 100% rename from .prettierignore rename to frontend/.prettierignore diff --git a/.prettierrc b/frontend/.prettierrc similarity index 100% rename from .prettierrc rename to frontend/.prettierrc diff --git a/package.json b/package.json deleted file mode 100644 index 43859cb..0000000 --- a/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "private": true, - "scripts": { - "build": "vite build", - "dev": "vite" - }, - "devDependencies": { - "@tailwindcss/vite": "^4.0.0", - "laravel-vite-plugin": "^1.0", - "tailwindcss": "^4.0.0", - "tailwindcss-animate": "^1.0.7", - "vite": "^6.0" - }, - "dependencies": { - "@tanstack/react-query": "^5.84.1", - "@types/react": "^19.1.9", - "@types/react-dom": "^19.1.7", - "@vitejs/plugin-react": "^4.7.0", - "axios": "^1.11.0", - "lucide-react": "^0.536.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", - "react-router-dom": "^7.7.1", - "typescript": "^5.9.2" - } -} diff --git a/resources/css/app.css b/resources/css/app.css deleted file mode 100644 index 43fdb4a..0000000 --- a/resources/css/app.css +++ /dev/null @@ -1,159 +0,0 @@ -@import 'tailwindcss'; - -@plugin 'tailwindcss-animate'; - -@source '../views'; -@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; - -@custom-variant dark (&:is(.dark *)); - -@theme { - --font-sans: - 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; - - --radius-lg: var(--radius); - --radius-md: calc(var(--radius) - 2px); - --radius-sm: calc(var(--radius) - 4px); - - --color-background: var(--background); - --color-foreground: var(--foreground); - - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - - --color-destructive: var(--destructive); - --color-destructive-foreground: var(--destructive-foreground); - - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); -} - -/* - The default border color has changed to `currentColor` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. -*/ -@layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentColor); - } -} - -:root { - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.87 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --radius: 0.625rem; - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.87 0 0); -} - -.dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.145 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.145 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.985 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.396 0.141 25.723); - --destructive-foreground: oklch(0.637 0.237 25.331); - --border: oklch(0.269 0 0); - --input: oklch(0.269 0 0); - --ring: oklch(0.439 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.985 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(0.269 0 0); - --sidebar-ring: oklch(0.439 0 0); -} - -@layer base { - * { - @apply border-border; - } - - body { - @apply bg-background text-foreground; - } -} diff --git a/resources/js/App.tsx b/resources/js/App.tsx deleted file mode 100644 index c597212..0000000 --- a/resources/js/App.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import { Routes, Route, Navigate } from 'react-router-dom'; -import { apiClient } from './lib/api'; -import Layout from './components/Layout'; -import Login from './pages/Login'; -import Dashboard from './pages/Dashboard'; -import Articles from './pages/Articles'; -import Feeds from './pages/Feeds'; -import Settings from './pages/Settings'; - -const App: React.FC = () => { - const isAuthenticated = apiClient.isAuthenticated(); - - if (!isAuthenticated) { - return ; - } - - return ( - - - } /> - } /> - } /> - } /> - } /> - } /> - - - ); -}; - -export default App; \ No newline at end of file diff --git a/resources/js/app.tsx b/resources/js/app.tsx deleted file mode 100644 index 6d10a91..0000000 --- a/resources/js/app.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; -import { BrowserRouter } from 'react-router-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import App from './App'; -import './bootstrap'; - -// Create React Query client -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: 1, - refetchOnWindowFocus: false, - }, - }, -}); - -// Get the root element -const container = document.getElementById('app'); -if (!container) { - throw new Error('Root element not found'); -} - -const root = createRoot(container); - -root.render( - - - - - - - -); \ No newline at end of file diff --git a/resources/js/bootstrap.ts b/resources/js/bootstrap.ts deleted file mode 100644 index d9785db..0000000 --- a/resources/js/bootstrap.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Bootstrap file for setting up global configurations - */ - -// Set up axios defaults -import axios from 'axios'; - -axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; -axios.defaults.headers.common['Accept'] = 'application/json'; -axios.defaults.headers.common['Content-Type'] = 'application/json'; - -// Add CSRF token if available -const token = document.head.querySelector('meta[name="csrf-token"]'); -if (token) { - axios.defaults.headers.common['X-CSRF-TOKEN'] = (token as HTMLMetaElement).content; -} - -// Set base URL for API calls -axios.defaults.baseURL = '/api/v1'; - -export default axios; \ No newline at end of file diff --git a/resources/js/components/Layout.tsx b/resources/js/components/Layout.tsx deleted file mode 100644 index c0618f1..0000000 --- a/resources/js/components/Layout.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import React from 'react'; -import { Link, useLocation } from 'react-router-dom'; -import { - Home, - FileText, - Rss, - Settings as SettingsIcon, - LogOut, - Menu, - X -} from 'lucide-react'; -import { apiClient } from '../lib/api'; - -interface LayoutProps { - children: React.ReactNode; -} - -const Layout: React.FC = ({ children }) => { - const [sidebarOpen, setSidebarOpen] = React.useState(false); - const location = useLocation(); - const user = apiClient.getUser(); - - const navigation = [ - { name: 'Dashboard', href: '/dashboard', icon: Home }, - { name: 'Articles', href: '/articles', icon: FileText }, - { name: 'Feeds', href: '/feeds', icon: Rss }, - { name: 'Settings', href: '/settings', icon: SettingsIcon }, - ]; - - const handleLogout = async () => { - try { - await apiClient.logout(); - window.location.reload(); - } catch (error) { - console.error('Logout failed:', error); - apiClient.clearAuth(); - window.location.reload(); - } - }; - - const renderMobileOverlay = () => { - if (!sidebarOpen) return null; - - return ( -
setSidebarOpen(false)} - /> - ); - }; - - return ( -
- {renderMobileOverlay()} - - {/* Mobile sidebar */} -
-
-

FFR

- -
- -
- - {/* Desktop sidebar */} -
-
-
-

FFR

-
- -
-
-
-

- {user?.name || 'User'} -

-

- {user?.email || 'user@example.com'} -

-
- -
-
-
-
- - {/* Main content */} -
-
- -
-

FFR

-
-
-
- {children} -
-
-
- ); -}; - -export default Layout; \ No newline at end of file diff --git a/resources/js/lib/api.ts b/resources/js/lib/api.ts deleted file mode 100644 index 2831652..0000000 --- a/resources/js/lib/api.ts +++ /dev/null @@ -1,288 +0,0 @@ -import axios from 'axios'; - -// Types for API responses -export interface ApiResponse { - success: boolean; - data: T; - message: string; -} - -export interface ApiError { - success: false; - message: string; - errors?: Record; -} - -export interface PaginatedResponse { - data: T[]; - pagination: { - current_page: number; - last_page: number; - per_page: number; - total: number; - from: number | null; - to: number | null; - }; -} - -// User types -export interface User { - id: number; - name: string; - email: string; -} - -export interface LoginCredentials { - email: string; - password: string; -} - -export interface RegisterData { - name: string; - email: string; - password: string; - password_confirmation: string; -} - -export interface AuthResponse { - user: User; - token: string; - token_type: string; -} - -// Article types -export interface Article { - id: number; - feed_id: number; - url: string; - title: string; - description: string; - is_valid: boolean; - is_duplicate: boolean; - approval_status: 'pending' | 'approved' | 'rejected'; - approved_at: string | null; - approved_by: string | null; - fetched_at: string | null; - validated_at: string | null; - created_at: string; - updated_at: string; - feed?: Feed; - article_publication?: ArticlePublication; -} - -// Feed types -export interface Feed { - id: number; - name: string; - url: string; - type: 'website' | 'rss'; - is_active: boolean; - description: string | null; - created_at: string; - updated_at: string; - articles_count?: number; -} - -// Other types -export interface ArticlePublication { - id: number; - article_id: number; - status: string; - published_at: string | null; - created_at: string; - updated_at: string; -} - -export interface PlatformAccount { - id: number; - platform_instance_id: number; - account_id: string; - username: string; - display_name: string | null; - description: string | null; - is_active: boolean; - created_at: string; - updated_at: string; -} - -export interface PlatformChannel { - id: number; - platform_instance_id: number; - channel_id: string; - name: string; - display_name: string | null; - description: string | null; - is_active: boolean; - created_at: string; - updated_at: string; -} - -export interface Settings { - article_processing_enabled: boolean; - publishing_approvals_enabled: boolean; -} - -export interface DashboardStats { - article_stats: { - total_today: number; - total_week: number; - total_month: number; - approved_today: number; - approved_week: number; - approved_month: number; - approval_percentage_today: number; - approval_percentage_week: number; - approval_percentage_month: number; - }; - system_stats: { - total_feeds: number; - active_feeds: number; - total_platform_accounts: number; - active_platform_accounts: number; - total_platform_channels: number; - active_platform_channels: number; - total_routes: number; - active_routes: number; - }; - available_periods: Array<{ value: string; label: string }>; - current_period: string; -} - -// API Client class -class ApiClient { - private token: string | null = null; - - constructor() { - // Get token from localStorage if available - this.token = localStorage.getItem('auth_token'); - this.setupInterceptors(); - } - - private setupInterceptors() { - // Request interceptor to add auth token - axios.interceptors.request.use((config) => { - if (this.token) { - config.headers.Authorization = `Bearer ${this.token}`; - } - return config; - }); - - // Response interceptor to handle errors - axios.interceptors.response.use( - (response) => response, - (error) => { - if (error.response?.status === 401) { - this.clearAuth(); - window.location.href = '/login'; - } - return Promise.reject(error); - } - ); - } - - setAuth(token: string, user: User) { - this.token = token; - localStorage.setItem('auth_token', token); - localStorage.setItem('user', JSON.stringify(user)); - } - - clearAuth() { - this.token = null; - localStorage.removeItem('auth_token'); - localStorage.removeItem('user'); - } - - getUser(): User | null { - const userStr = localStorage.getItem('user'); - return userStr ? JSON.parse(userStr) : null; - } - - isAuthenticated(): boolean { - return !!this.token; - } - - // Auth endpoints - async login(credentials: LoginCredentials): Promise { - const response = await axios.post>('/auth/login', credentials); - return response.data.data; - } - - async register(data: RegisterData): Promise { - const response = await axios.post>('/auth/register', data); - return response.data.data; - } - - async logout(): Promise { - await axios.post('/auth/logout'); - this.clearAuth(); - } - - async me(): Promise { - const response = await axios.get>('/auth/me'); - return response.data.data.user; - } - - // Dashboard endpoints - async getDashboardStats(period = 'today'): Promise { - const response = await axios.get>('/dashboard/stats', { - params: { period } - }); - return response.data.data; - } - - // Articles endpoints - async getArticles(page = 1, perPage = 15): Promise<{ articles: Article[]; pagination: any; settings: any }> { - const response = await axios.get>('/articles', { - params: { page, per_page: perPage } - }); - return response.data.data; - } - - async approveArticle(articleId: number): Promise
{ - const response = await axios.post>(`/articles/${articleId}/approve`); - return response.data.data; - } - - async rejectArticle(articleId: number): Promise
{ - const response = await axios.post>(`/articles/${articleId}/reject`); - return response.data.data; - } - - // Feeds endpoints - async getFeeds(): Promise { - const response = await axios.get>('/feeds'); - return response.data.data; - } - - async createFeed(data: Partial): Promise { - const response = await axios.post>('/feeds', data); - return response.data.data; - } - - async updateFeed(id: number, data: Partial): Promise { - const response = await axios.put>(`/feeds/${id}`, data); - return response.data.data; - } - - async deleteFeed(id: number): Promise { - await axios.delete(`/feeds/${id}`); - } - - async toggleFeed(id: number): Promise { - const response = await axios.post>(`/feeds/${id}/toggle`); - return response.data.data; - } - - // Settings endpoints - async getSettings(): Promise { - const response = await axios.get>('/settings'); - return response.data.data; - } - - async updateSettings(data: Partial): Promise { - const response = await axios.put>('/settings', data); - return response.data.data; - } -} - -export const apiClient = new ApiClient(); \ No newline at end of file diff --git a/resources/js/pages/Articles.tsx b/resources/js/pages/Articles.tsx deleted file mode 100644 index 9fba560..0000000 --- a/resources/js/pages/Articles.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import React, { useState } from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { CheckCircle, XCircle, ExternalLink, Calendar, Tag, FileText } from 'lucide-react'; -import { apiClient, Article } from '../lib/api'; - -const Articles: React.FC = () => { - const [page, setPage] = useState(1); - const queryClient = useQueryClient(); - - const { data, isLoading, error } = useQuery({ - queryKey: ['articles', page], - queryFn: () => apiClient.getArticles(page), - }); - - const approveMutation = useMutation({ - mutationFn: (articleId: number) => apiClient.approveArticle(articleId), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['articles'] }); - }, - }); - - const rejectMutation = useMutation({ - mutationFn: (articleId: number) => apiClient.rejectArticle(articleId), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['articles'] }); - }, - }); - - const handleApprove = (articleId: number) => { - approveMutation.mutate(articleId); - }; - - const handleReject = (articleId: number) => { - rejectMutation.mutate(articleId); - }; - - const getStatusBadge = (status: string) => { - switch (status) { - case 'approved': - return ( - - - Approved - - ); - case 'rejected': - return ( - - - Rejected - - ); - default: - return ( - - - Pending - - ); - } - }; - - if (isLoading) { - return ( -
-
-
-
- {[...Array(5)].map((_, i) => ( -
-
-
-
-
-
-
-
- ))} -
-
-
- ); - } - - if (error) { - return ( -
-
-

Failed to load articles

-
-
- ); - } - - const articles = data?.articles || []; - const pagination = data?.pagination; - const settings = data?.settings; - - return ( -
-
-

Articles

-

- Manage and review articles from your feeds -

- {settings?.publishing_approvals_enabled && ( -
- - Approval system enabled -
- )} -
- -
- {articles.map((article: Article) => ( -
-
-
-

- {article.title || 'Untitled Article'} -

-

- {article.description || 'No description available'} -

-
- Feed: {article.feed?.name || 'Unknown'} - - {new Date(article.created_at).toLocaleDateString()} - {article.is_valid !== null && ( - <> - - - {article.is_valid ? 'Valid' : 'Invalid'} - - - )} - {article.is_duplicate && ( - <> - - Duplicate - - )} -
-
-
- {getStatusBadge(article.approval_status)} - - - -
-
- - {article.approval_status === 'pending' && settings?.publishing_approvals_enabled && ( -
- - -
- )} -
- ))} - - {articles.length === 0 && ( -
- -

No articles

-

- No articles have been fetched yet. -

-
- )} - - {/* Pagination */} - {pagination && pagination.last_page > 1 && ( -
-
- - -
-
-
-

- Showing{' '} - {pagination.from} to{' '} - {pagination.to} of{' '} - {pagination.total} results -

-
-
- -
-
-
- )} -
-
- ); -}; - -export default Articles; \ No newline at end of file diff --git a/resources/js/pages/Dashboard.tsx b/resources/js/pages/Dashboard.tsx deleted file mode 100644 index 24a130e..0000000 --- a/resources/js/pages/Dashboard.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import React from 'react'; -import { useQuery } from '@tanstack/react-query'; -import { FileText, Rss, Users, Route, TrendingUp, Clock, CheckCircle } from 'lucide-react'; -import { apiClient } from '../lib/api'; - -const Dashboard: React.FC = () => { - const { data: stats, isLoading, error } = useQuery({ - queryKey: ['dashboard-stats'], - queryFn: () => apiClient.getDashboardStats(), - }); - - if (isLoading) { - return ( -
-
-
-
- {[...Array(4)].map((_, i) => ( -
-
-
-
- ))} -
-
-
- ); - } - - if (error) { - return ( -
-
-

Failed to load dashboard data

-
-
- ); - } - - const articleStats = stats?.article_stats; - const systemStats = stats?.system_stats; - - return ( -
-
-

Dashboard

-

- Overview of your feed management system -

-
- - {/* Article Statistics */} -
-

Article Statistics

-
-
-
-
- -
-
-

Articles Today

-

- {articleStats?.total_today || 0} -

-
-
-
- -
-
-
- -
-
-

Articles This Week

-

- {articleStats?.total_week || 0} -

-
-
-
- -
-
-
- -
-
-

Approved Today

-

- {articleStats?.approved_today || 0} -

-
-
-
- -
-
-
- -
-
-

Approval Rate

-

- {articleStats?.approval_percentage_today?.toFixed(1) || 0}% -

-
-
-
-
-
- - {/* System Statistics */} -
-

System Overview

-
-
-
-
- -
-
-

Active Feeds

-

- {systemStats?.active_feeds || 0} - - /{systemStats?.total_feeds || 0} - -

-
-
-
- -
-
-
- -
-
-

Platform Accounts

-

- {systemStats?.active_platform_accounts || 0} - - /{systemStats?.total_platform_accounts || 0} - -

-
-
-
- -
-
-
- -
-
-

Platform Channels

-

- {systemStats?.active_platform_channels || 0} - - /{systemStats?.total_platform_channels || 0} - -

-
-
-
- -
-
-
- -
-
-

Active Routes

-

- {systemStats?.active_routes || 0} - - /{systemStats?.total_routes || 0} - -

-
-
-
-
-
-
- ); -}; - -export default Dashboard; \ No newline at end of file diff --git a/resources/js/pages/Feeds.tsx b/resources/js/pages/Feeds.tsx deleted file mode 100644 index e366ae5..0000000 --- a/resources/js/pages/Feeds.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import React from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { Rss, Globe, ToggleLeft, ToggleRight, ExternalLink } from 'lucide-react'; -import { apiClient, Feed } from '../lib/api'; - -const Feeds: React.FC = () => { - const queryClient = useQueryClient(); - - const { data: feeds, isLoading, error } = useQuery({ - queryKey: ['feeds'], - queryFn: () => apiClient.getFeeds(), - }); - - const toggleMutation = useMutation({ - mutationFn: (feedId: number) => apiClient.toggleFeed(feedId), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['feeds'] }); - }, - }); - - const handleToggle = (feedId: number) => { - toggleMutation.mutate(feedId); - }; - - const getTypeIcon = (type: string) => { - switch (type) { - case 'rss': - return ; - case 'website': - return ; - default: - return ; - } - }; - - if (isLoading) { - return ( -
-
-
-
- {[...Array(6)].map((_, i) => ( -
-
-
-
-
- ))} -
-
-
- ); - } - - if (error) { - return ( -
-
-

Failed to load feeds

-
-
- ); - } - - return ( -
-
-

Feeds

-

- Manage your RSS feeds and website sources -

-
- -
- {feeds?.map((feed: Feed) => ( -
-
-
- {getTypeIcon(feed.type)} -

- {feed.name} -

-
- -
- -

- {feed.description || 'No description provided'} -

- -
-
- - {feed.is_active ? 'Active' : 'Inactive'} - - - {feed.type.toUpperCase()} - -
- - - -
- -
- Added {new Date(feed.created_at).toLocaleDateString()} -
-
- ))} - - {feeds?.length === 0 && ( -
- -

No feeds

-

- Get started by adding your first feed. -

-
- )} -
-
- ); -}; - -export default Feeds; \ No newline at end of file diff --git a/resources/js/pages/Login.tsx b/resources/js/pages/Login.tsx deleted file mode 100644 index 5e24d15..0000000 --- a/resources/js/pages/Login.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import React, { useState } from 'react'; -import { Eye, EyeOff, LogIn } from 'lucide-react'; -import { apiClient } from '../lib/api'; - -const Login: React.FC = () => { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [showPassword, setShowPassword] = useState(false); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(''); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - setError(''); - - try { - const authData = await apiClient.login({ email, password }); - apiClient.setAuth(authData.token, authData.user); - window.location.reload(); - } catch (err: any) { - setError(err.response?.data?.message || 'Login failed. Please try again.'); - } finally { - setLoading(false); - } - }; - - return ( -
-
-
- FFR -
-

- Sign in to FFR -

-

- Feed Feed Reader - Article Management System -

-
- -
-
-
- {error && ( -
-

{error}

-
- )} - -
- -
- setEmail(e.target.value)} - className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" - placeholder="Enter your email" - /> -
-
- -
- -
- setPassword(e.target.value)} - className="appearance-none block w-full px-3 py-2 pr-10 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" - placeholder="Enter your password" - /> - -
-
- -
- -
-
- -
-
- Demo credentials: test@example.com / password123 -
-
-
-
-
- ); -}; - -export default Login; \ No newline at end of file diff --git a/resources/js/pages/Settings.tsx b/resources/js/pages/Settings.tsx deleted file mode 100644 index e82df99..0000000 --- a/resources/js/pages/Settings.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import React from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { Settings as SettingsIcon, Save, ToggleLeft, ToggleRight } from 'lucide-react'; -import { apiClient } from '../lib/api'; - -const Settings: React.FC = () => { - const queryClient = useQueryClient(); - - const { data: settings, isLoading, error } = useQuery({ - queryKey: ['settings'], - queryFn: () => apiClient.getSettings(), - }); - - const updateMutation = useMutation({ - mutationFn: (data: any) => apiClient.updateSettings(data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['settings'] }); - }, - }); - - const handleToggle = (key: string, value: boolean) => { - updateMutation.mutate({ [key]: value }); - }; - - if (isLoading) { - return ( -
-
-
-
-
-
-
-
-
-
-
-
-
-
- ); - } - - if (error) { - return ( -
-
-

Failed to load settings

-
-
- ); - } - - return ( -
-
-

Settings

-

- Configure your system preferences -

-
- -
- {/* Article Processing Settings */} -
-
-

- - Article Processing -

-

- Control how articles are processed and handled -

-
-
-
-
-

- Article Processing Enabled -

-

- Enable automatic fetching and processing of articles from feeds -

-
- -
- -
-
-

- Publishing Approvals Required -

-

- Require manual approval before articles are published to platforms -

-
- -
-
-
- - {/* Status indicator */} - {updateMutation.isPending && ( -
-
-
-

Updating settings...

-
-
- )} - - {updateMutation.isError && ( -
-

Failed to update settings. Please try again.

-
- )} - - {updateMutation.isSuccess && ( -
-

Settings updated successfully!

-
- )} -
-
- ); -}; - -export default Settings; \ No newline at end of file diff --git a/resources/js/routing.js b/resources/js/routing.js deleted file mode 100644 index 8862f65..0000000 --- a/resources/js/routing.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Routing page JavaScript functionality - * Handles dynamic keyword input management - */ - -function addKeyword() { - const container = document.getElementById('keywords-container'); - const newGroup = document.createElement('div'); - newGroup.className = 'keyword-input-group flex items-center space-x-2'; - newGroup.innerHTML = ` - - - `; - container.appendChild(newGroup); -} - -function removeKeyword(button) { - const container = document.getElementById('keywords-container'); - const groups = container.querySelectorAll('.keyword-input-group'); - - // Don't remove if it's the last remaining input - if (groups.length > 1) { - button.parentElement.remove(); - } else { - // Clear the input value instead of removing the field - const input = button.parentElement.querySelector('input'); - input.value = ''; - } -} - -// Make functions globally available for onclick handlers -window.addKeyword = addKeyword; -window.removeKeyword = removeKeyword; \ No newline at end of file diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php deleted file mode 100644 index e1b292d..0000000 --- a/resources/views/app.blade.php +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - {{ config('app.name', 'FFR') }} - - - - - - - - -
- - - - - \ No newline at end of file diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php deleted file mode 100644 index 355c64d..0000000 --- a/resources/views/layouts/app.blade.php +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - @yield('title', 'Lemmy Poster Admin') - - @vite(['resources/css/app.css', 'resources/js/app.js']) - - -
- @include('partials.sidebar') - - -
- -
-
-

@yield('page-title', 'Dashboard')

-
-
- - -
- @yield('content') -
-
-
- - diff --git a/resources/views/onboarding/channel.blade.php b/resources/views/onboarding/channel.blade.php deleted file mode 100644 index 5367e37..0000000 --- a/resources/views/onboarding/channel.blade.php +++ /dev/null @@ -1,110 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Configure Your Channel

-

- Set up a Lemmy community where articles will be posted -

- - -
-
-
-
3
-
4
-
-
- -
- @csrf - -
- - -

Enter the community name (without the @ or instance)

- @error('name') -

{{ $message }}

- @enderror -
- -
- - - @error('platform_instance_id') -

{{ $message }}

- @enderror -
- -
- - - @error('language_id') -

{{ $message }}

- @enderror -
- -
- - - @error('description') -

{{ $message }}

- @enderror -
- - - - -
- - ← Back - - -
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/onboarding/complete.blade.php b/resources/views/onboarding/complete.blade.php deleted file mode 100644 index e90b867..0000000 --- a/resources/views/onboarding/complete.blade.php +++ /dev/null @@ -1,121 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-
-
- - - -
-

Setup Complete!

-

- Great! You've successfully configured Lemmy Poster. Now activate the system to start monitoring feeds and posting articles. -

-
- - -
-
-
-
-
-
- - -
-
-
-
- @if($systemStatus['is_enabled']) -
- -
-
-

System Status

-

{{ $systemStatus['status'] }}

-
- @else -
- -
-
-

Ready to Activate

-

System is configured but not active

-
- @endif -
- - @if(!$systemStatus['is_enabled']) -
- @csrf - @method('PUT') - - - -
- @else - ✓ Active - @endif -
- - @if(!$systemStatus['is_enabled'] && count($systemStatus['reasons']) > 0) -
-

System will be enabled once activated. Current setup status:

-
    - @foreach($systemStatus['reasons'] as $reason) - @if($reason !== 'Manually disabled by user') -
  • - - {{ str_replace('No active', 'Active', $reason) . ' ✓' }} -
  • - @endif - @endforeach -
-
- @endif -
-
- -
-
-

What happens next?

-
    -
  • • Your feeds will be checked regularly for new articles
  • -
  • • New articles will be automatically posted to your channels
  • -
  • • You can monitor activity in the Articles and Logs sections
  • -
-
- -
-

Want more control?

-

- Set up routing rules to control which articles get posted where based on keywords, titles, or content. -

- - Configure Routing → - -
-
- - -
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/onboarding/feed.blade.php b/resources/views/onboarding/feed.blade.php deleted file mode 100644 index 46f0ef8..0000000 --- a/resources/views/onboarding/feed.blade.php +++ /dev/null @@ -1,123 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Add Your First Feed

-

- Add a RSS feed or website to monitor for new articles -

- - -
-
-
2
-
3
-
4
-
-
- -
- @csrf - -
- - - @error('name') -

{{ $message }}

- @enderror -
- -
- - - @error('url') -

{{ $message }}

- @enderror -
- -
- - - @error('type') -

{{ $message }}

- @enderror -
- -
- - - @error('language_id') -

{{ $message }}

- @enderror -
- -
- - - @error('description') -

{{ $message }}

- @enderror -
- - - - -
- - ← Back - - -
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/onboarding/platform.blade.php b/resources/views/onboarding/platform.blade.php deleted file mode 100644 index 6c1424e..0000000 --- a/resources/views/onboarding/platform.blade.php +++ /dev/null @@ -1,86 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Connect Your Lemmy Account

-

- Enter your Lemmy instance details and login credentials -

- - -
-
1
-
2
-
3
-
4
-
-
- -
- @csrf - -
- - - @error('instance_url') -

{{ $message }}

- @enderror -
- -
- - - @error('username') -

{{ $message }}

- @enderror -
- -
- - - @error('password') -

{{ $message }}

- @enderror -
- - - - - -
- - ← Back - - -
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/onboarding/welcome.blade.php b/resources/views/onboarding/welcome.blade.php deleted file mode 100644 index 44d345f..0000000 --- a/resources/views/onboarding/welcome.blade.php +++ /dev/null @@ -1,40 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Welcome to Lemmy Poster

-

- Let's get you set up! We'll help you configure your Lemmy account, add your first feed, and create a channel for posting. -

- -
-
-
1
- Connect your Lemmy account -
-
-
2
- Add your first feed -
-
-
3
- Configure a channel -
-
-
4
- You're ready to go! -
-
- - -
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/articles/index.blade.php b/resources/views/pages/articles/index.blade.php deleted file mode 100644 index 535ce9f..0000000 --- a/resources/views/pages/articles/index.blade.php +++ /dev/null @@ -1,79 +0,0 @@ -@extends('layouts.app') - -@section('page-title', 'Articles') - -@section('content') -
-
-

Article Feed

-
- -
- - - - - - - - - - - - - @foreach($articles as $article) - - - - - - - - - @endforeach - -
IDURLStatusApprovalCreated AtActions
{{ $article->id }} - - {{ Str::limit($article->url, 60) }} - - - - {{ $article->articlePublication ? 'Published' : 'Pending' }} - - - - {{ ucfirst($article->approval_status) }} - - {{ $article->created_at->format('Y-m-d H:i') }} - @if($publishingApprovalsEnabled && $article->isValid() && $article->isPending() && !$article->articlePublication) -
-
- @csrf - -
-
- @csrf - -
-
- @elseif($article->isValid() && !$article->articlePublication) - Auto-publishing enabled - @endif -
-
- - @if($articles->hasPages()) -
- {{ $articles->links() }} -
- @endif -
-@endsection diff --git a/resources/views/pages/channels/create.blade.php b/resources/views/pages/channels/create.blade.php deleted file mode 100644 index 0e18bc7..0000000 --- a/resources/views/pages/channels/create.blade.php +++ /dev/null @@ -1,100 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Create New Channel

-

Add a new publishing channel to your platform

-
- -
-
- @csrf - -
-
- - - @error('platform_instance_id') -

{{ $message }}

- @enderror -
- -
- - -

The channel identifier (e.g., "technology", "news")

- @error('name') -

{{ $message }}

- @enderror -
- -
- - -

Human-readable name for the channel (optional)

- @error('display_name') -

{{ $message }}

- @enderror -
- -
- - -

Platform-specific channel ID (optional)

- @error('channel_id') -

{{ $message }}

- @enderror -
- -
- - - @error('description') -

{{ $message }}

- @enderror -
- -
- - -
-
- -
- - Cancel - - -
-
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/channels/edit.blade.php b/resources/views/pages/channels/edit.blade.php deleted file mode 100644 index b1acfef..0000000 --- a/resources/views/pages/channels/edit.blade.php +++ /dev/null @@ -1,104 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Edit Channel

-

Update channel details

-
- -
-
- @csrf - @method('PUT') - -
-
- - - @error('platform_instance_id') -

{{ $message }}

- @enderror -
- -
- - - @error('name') -

{{ $message }}

- @enderror -
- -
- - - @error('display_name') -

{{ $message }}

- @enderror -
- -
- - - @error('channel_id') -

{{ $message }}

- @enderror -
- -
- - - @error('description') -

{{ $message }}

- @enderror -
- -
- is_active) ? 'checked' : '' }} - class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"> - -
-
- -
- - @csrf - @method('DELETE') - - - -
- - Cancel - - -
-
- -
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/channels/index.blade.php b/resources/views/pages/channels/index.blade.php deleted file mode 100644 index b999c70..0000000 --- a/resources/views/pages/channels/index.blade.php +++ /dev/null @@ -1,99 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-
-

Platform Channels

-

Manage channels for publishing content

-
- - Add New Channel - -
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - -
- @if($channels->count() > 0) -
    - @foreach($channels as $channel) -
  • -
    -
    -
    - -
    -
    -
    -
    {{ $channel->display_name ?? $channel->name }}
    - @if(!$channel->is_active) - - Inactive - - @else - - Active - - @endif - - {{ $channel->platformInstance->name }} - -
    -
    {{ $channel->name }}
    - @if($channel->description) -
    {{ Str::limit($channel->description, 100) }}
    - @endif -
    -
    -
    - -
    - @csrf - -
    - - - - View - - - Edit - -
    - @csrf - @method('DELETE') - -
    -
    -
    -
  • - @endforeach -
- @else -
- -

No channels yet

-

Get started by adding your first publishing channel.

- - Add New Channel - -
- @endif -
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/channels/show.blade.php b/resources/views/pages/channels/show.blade.php deleted file mode 100644 index f70f8bb..0000000 --- a/resources/views/pages/channels/show.blade.php +++ /dev/null @@ -1,177 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
- -
-
-

{{ $channel->display_name ?? $channel->name }}

-

{{ $channel->platformInstance->name }} Channel

-
- -
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - -
- -
-
-
-
-

Channel Status

-

Enable or disable publishing to this channel

-
- @if($channel->is_active) -
- -
- @else -
- -
- @endif -
- -
- - {{ $channel->is_active ? 'Active' : 'Inactive' }} - - -
- @csrf - -
-
- - @if(!$channel->is_active) -
-

- - This channel is inactive. No articles will be published here until reactivated. -

-
- @endif -
-
- - -
-
-

Channel Details

- -
-
-
Channel Name
-
{{ $channel->name }}
-
- -
-
Display Name
-
{{ $channel->display_name ?? $channel->name }}
-
- -
-
Platform
-
{{ $channel->platformInstance->name }}
-
- -
-
Channel ID
-
{{ $channel->channel_id ?? 'Not set' }}
-
- - @if($channel->language) -
-
Language
-
{{ $channel->language->name }}
-
- @endif - -
-
Created
-
{{ $channel->created_at->format('M j, Y') }}
-
-
- - @if($channel->description) -
-
Description
-
{{ $channel->description }}
-
- @endif -
-
-
- - - @if($channel->feeds->count() > 0) -
-
-

Connected Feeds

-

Feeds that route content to this channel

-
-
    - @foreach($channel->feeds as $feed) -
  • -
    -
    - @if($feed->type === 'rss') - - @else - - @endif -
    -

    {{ $feed->name }}

    -

    {{ $feed->url }}

    -
    - @if(!$feed->pivot->is_active) - - Route Inactive - - @endif -
    - -
    -
  • - @endforeach -
-
- @else -
-
- -

No feeds connected

-

This channel doesn't have any feeds routing content to it yet.

- - Create Route - -
-
- @endif -
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/dashboard.blade.php b/resources/views/pages/dashboard.blade.php deleted file mode 100644 index 91ce35d..0000000 --- a/resources/views/pages/dashboard.blade.php +++ /dev/null @@ -1,249 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Dashboard

- - -
- - -
-
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - - -
- -
-
-
-
- -
-
-
-
Articles Fetched
-
{{ number_format($stats['articles_fetched']) }}
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
Articles Published
-
{{ number_format($stats['articles_published']) }}
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
Published Rate
-
{{ $stats['published_percentage'] }}%
-
-
-
-
-
-
- -
- -
-
-
-
- @if($systemStatus['is_enabled']) -
- -
- @else -
- -
- @endif -
-
-
-
System Status
-
- {{ $systemStatus['status'] }} -
-
-
-
- - @if(!$systemStatus['is_enabled'] && count($systemStatus['reasons']) > 0) -
-

Reasons for being disabled:

-
    - @foreach($systemStatus['reasons'] as $reason) -
  • - - {{ $reason }} -
  • - @endforeach -
-
- @endif - - @if(!$systemStatus['is_enabled']) - - @endif -
-
- - -
-
-
-
- -
-
-

System Configuration

-
-
- -
-
- Feeds - {{ $systemStats['active_feeds'] }}/{{ $systemStats['total_feeds'] }} -
-
- Channels - {{ $systemStats['active_channels'] }}/{{ $systemStats['total_channels'] }} -
-
- Routes - {{ $systemStats['active_routes'] }}/{{ $systemStats['total_routes'] }} -
-
-
-
- - -
-
-
-
- -
-
-
-
Recent Activity
-
- View Logs -
-
-
-
-
-
-
- - - -
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/feeds/create.blade.php b/resources/views/pages/feeds/create.blade.php deleted file mode 100644 index 08af8a4..0000000 --- a/resources/views/pages/feeds/create.blade.php +++ /dev/null @@ -1,109 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Add New Feed

-

Create a new content feed for articles.

-
- -
-
- @csrf - -
-
- - - @error('name') -

{{ $message }}

- @enderror -
- -
- - - @error('url') -

{{ $message }}

- @enderror -
- -
- - - @error('type') -

{{ $message }}

- @enderror -
- -
- - - @error('language') -

{{ $message }}

- @enderror -
- -
- - - @error('description') -

{{ $message }}

- @enderror -
- -
- - -
-
- -
- - Cancel - - -
-
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/feeds/edit.blade.php b/resources/views/pages/feeds/edit.blade.php deleted file mode 100644 index d761591..0000000 --- a/resources/views/pages/feeds/edit.blade.php +++ /dev/null @@ -1,110 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Edit Feed

-

Update the details for {{ $feed->name }}.

-
- -
-
- @csrf - @method('PUT') - -
-
- - - @error('name') -

{{ $message }}

- @enderror -
- -
- - - @error('url') -

{{ $message }}

- @enderror -
- -
- - - @error('type') -

{{ $message }}

- @enderror -
- -
- - - @error('language') -

{{ $message }}

- @enderror -
- -
- - - @error('description') -

{{ $message }}

- @enderror -
- -
- is_active) ? 'checked' : '' }} - class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"> - -
-
- -
- - Cancel - - -
-
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/feeds/index.blade.php b/resources/views/pages/feeds/index.blade.php deleted file mode 100644 index c5d5602..0000000 --- a/resources/views/pages/feeds/index.blade.php +++ /dev/null @@ -1,99 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Feeds

- - Add New Feed - -
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - -
- @if($feeds->count() > 0) -
    - @foreach($feeds as $feed) -
  • -
    -
    -
    - @if($feed->type === 'rss') - - @else - - @endif -
    -
    -
    -
    {{ $feed->name }}
    - - {{ $feed->is_active ? 'Active' : 'Inactive' }} - - - {{ $feed->type_display }} - - - {{ strtoupper($feed->language) }} - -
    -
    {{ $feed->url }}
    - @if($feed->description) -
    {{ Str::limit($feed->description, 100) }}
    - @endif -
    {{ $feed->status }}
    -
    -
    -
    - -
    - @csrf - -
    - - - - View - - - Edit - -
    - @csrf - @method('DELETE') - -
    -
    -
    -
  • - @endforeach -
- @else -
- -

No feeds yet

-

Get started by adding your first content feed.

- - Add New Feed - -
- @endif -
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/feeds/show.blade.php b/resources/views/pages/feeds/show.blade.php deleted file mode 100644 index c32eb2d..0000000 --- a/resources/views/pages/feeds/show.blade.php +++ /dev/null @@ -1,141 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-
-
-

{{ $feed->name }}

-

{{ $feed->type_display }} • {{ strtoupper($feed->language) }}

-
-
- -
- @csrf - -
- - - Edit Feed - -
-
-
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - - @if(!$feed->is_active) -
-
-
- -
-
-

- This feed is inactive. No articles will be fetched or published from this feed until reactivated. -

-
-
-
- @endif - -
-
-

Feed Details

-

Information about this content feed.

-
-
-
-
-
Name
-
{{ $feed->name }}
-
- -
-
Type
-
-
- @if($feed->type === 'rss') - - @else - - @endif - {{ $feed->type_display }} -
-
-
- - - -
-
Language
-
{{ strtoupper($feed->language) }}
-
- -
-
Status
-
{{ $feed->status }}
-
- -
-
Created
-
{{ $feed->created_at->format('M j, Y g:i A') }}
-
- - @if($feed->last_fetched_at) -
-
Last Fetched
-
{{ $feed->last_fetched_at->format('M j, Y g:i A') }}
-
- @endif - - @if($feed->description) -
-
Description
-
{{ $feed->description }}
-
- @endif -
-
-
- -
- - ← Back to Feeds - - -
- - Edit - -
- @csrf - @method('DELETE') - -
-
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/logs/index.blade.php b/resources/views/pages/logs/index.blade.php deleted file mode 100644 index 58cd318..0000000 --- a/resources/views/pages/logs/index.blade.php +++ /dev/null @@ -1,40 +0,0 @@ -@extends('layouts.app') - -@section('page-title', 'System Logs') - -@section('content') -
-
-

Recent Logs

-
- -
- - - - - - - - - - - @foreach($logs as $log) - - - - - - - @endforeach - -
IDLevelMessageCreated At
{{ $log->id }} - - {{ ucfirst($log->level->value) }} - - {{ Str::limit($log->message, 100) }}{{ $log->created_at->format('Y-m-d H:i') }}
-
-
-@endsection diff --git a/resources/views/pages/platforms/index.blade.php b/resources/views/pages/platforms/index.blade.php deleted file mode 100644 index 83227b8..0000000 --- a/resources/views/pages/platforms/index.blade.php +++ /dev/null @@ -1,103 +0,0 @@ -@extends('layouts.app') - -@section('page-title', 'Platform Accounts') - -@section('content') - - -
-
-

Platform Accounts

-

Manage your social media platform accounts for posting

-
- - @if($accounts->isEmpty()) -
- -

No platform accounts configured

-

Add your first platform account to start posting articles

- - - Add Platform Account - -
- @else -
- - - - - - - - - - - - @foreach($accounts as $account) - - - - - - - - @endforeach - -
PlatformAccountStatusLast TestedActions
-
- - {{ $account->platform }} - @if($account->is_active) - - Active - - @endif -
-
-
{{ $account->username }}
-
{{ $account->instance_url }}
-
- - {{ ucfirst($account->status) }} - - - {{ $account->last_tested_at ? $account->last_tested_at->format('Y-m-d H:i') : 'Never' }} - -
- @if(!$account->is_active) -
- @csrf - -
- @endif - - - Edit - - -
- @csrf - @method('DELETE') - -
-
-
-
- @endif -
-@endsection \ No newline at end of file diff --git a/resources/views/pages/routing/create.blade.php b/resources/views/pages/routing/create.blade.php deleted file mode 100644 index 5da8e02..0000000 --- a/resources/views/pages/routing/create.blade.php +++ /dev/null @@ -1,159 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Create Feed Routing

-

Route a feed to one or more channels.

-
- -
-
- @csrf - -
-
- - - @error('feed_id') -

{{ $message }}

- @enderror -
- -
- -
- @forelse($channels as $channel) -
- id, old('channel_ids', [])) ? 'checked' : '' }} - class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"> - -
- @empty -

No active channels available. Please create channels first.

- @endforelse -
- @error('channel_ids') -

{{ $message }}

- @enderror - @error('channel_ids.*') -

{{ $message }}

- @enderror -
- -
- - -

Higher numbers = higher priority (0-100)

- @error('priority') -

{{ $message }}

- @enderror -
- -
- -
-
- - -
-
- -

Articles will be filtered to only include content matching these keywords

- @error('keywords') -

{{ $message }}

- @enderror - @error('keywords.*') -

{{ $message }}

- @enderror -
- -
- - -

JSON format for additional content filtering rules

- @error('filters') -

{{ $message }}

- @enderror -
-
- -
- - Cancel - - -
-
-
- - @if($feeds->isEmpty() || $channels->isEmpty()) -
-
-
- -
-
-

Prerequisites Missing

-
-

To create routing, you need:

-
    - @if($feeds->isEmpty()) -
  • At least one active feed
  • - @endif - @if($channels->isEmpty()) -
  • At least one active channel
  • - @endif -
-
-
-
-
- @endif -
-
- -@vite('resources/js/routing.js') -@endsection \ No newline at end of file diff --git a/resources/views/pages/routing/edit.blade.php b/resources/views/pages/routing/edit.blade.php deleted file mode 100644 index 65a2b79..0000000 --- a/resources/views/pages/routing/edit.blade.php +++ /dev/null @@ -1,131 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Edit Routing

-

- {{ $feed->name }} → {{ $channel->name }} ({{ $channel->platformInstance->name }}) -

-
- -
-
- @csrf - @method('PUT') - -
-
-

Routing Details

-
-
-
- Feed: -
- @if($feed->type === 'rss') - - @else - - @endif - {{ $feed->name }} -
-
-
- Channel: -
- - {{ $channel->name }} - ({{ $channel->platformInstance->name }}) -
-
-
-
-
- -
- pivot->is_active) ? 'checked' : '' }} - class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"> - -
- -
- - -

Higher numbers = higher priority (0-100)

- @error('priority') -

{{ $message }}

- @enderror -
- -
- - -

JSON format for content filtering rules

- @error('filters') -

{{ $message }}

- @enderror -
- -
-
-
- -
-
-

Filter Examples

-
-

You can use filters to control which content gets routed:

-
    -
  • {"keywords": ["tech", "AI"]} - Include only articles with these keywords
  • -
  • {"exclude_keywords": ["sports"]} - Exclude articles with these keywords
  • -
  • {"min_length": 500} - Minimum article length
  • -
  • {"max_age_hours": 24} - Only articles from last 24 hours
  • -
-
-
-
-
-
- -
- - @csrf - @method('DELETE') - - - -
- - Cancel - - -
-
- -
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/routing/index.blade.php b/resources/views/pages/routing/index.blade.php deleted file mode 100644 index 6fd6458..0000000 --- a/resources/views/pages/routing/index.blade.php +++ /dev/null @@ -1,154 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-
-

Feed Routing

-

Manage how feeds are routed to channels

-
- - Create New Routing - -
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - -
- -
-
-

Feeds → Channels

-

Active feed-to-channel routing

-
-
- @forelse($feeds as $feed) - @if($feed->channels->count() > 0) -
-
- @if($feed->type === 'rss') - - @else - - @endif - {{ $feed->name }} - - {{ $feed->channels->count() }} channel{{ $feed->channels->count() !== 1 ? 's' : '' }} - -
-
- @foreach($feed->channels as $channel) -
-
- - {{ $channel->name }} - ({{ $channel->platformInstance->name }}) - @if(!$channel->pivot->is_active) - - Inactive - - @endif - @if($channel->pivot->priority > 0) - - Priority: {{ $channel->pivot->priority }} - - @endif -
-
-
- @csrf - -
- Edit -
- @csrf - @method('DELETE') - -
-
-
- @endforeach -
-
- @endif - @empty -
- No feed routing configured -
- @endforelse -
-
- - -
-
-

Channels ← Feeds

-

Channels and their connected feeds

-
-
- @forelse($channels as $channel) - @if($channel->feeds->count() > 0) -
-
- - {{ $channel->name }} - ({{ $channel->platformInstance->name }}) - - {{ $channel->feeds->count() }} feed{{ $channel->feeds->count() !== 1 ? 's' : '' }} - -
-
- @foreach($channel->feeds as $feed) -
-
- @if($feed->type === 'rss') - - @else - - @endif - {{ $feed->name }} - @if(!$feed->pivot->is_active) - - Inactive - - @endif -
- Edit -
- @endforeach -
-
- @endif - @empty -
- No channels with feeds -
- @endforelse -
-
-
- - @if($feeds->where('channels')->isEmpty() && $channels->where('feeds')->isEmpty()) -
- -

No routing configured

-

Connect your feeds to channels to start routing content.

- - Create First Routing - -
- @endif -
-
-@endsection \ No newline at end of file diff --git a/resources/views/pages/settings/index.blade.php b/resources/views/pages/settings/index.blade.php deleted file mode 100644 index 7c1df5d..0000000 --- a/resources/views/pages/settings/index.blade.php +++ /dev/null @@ -1,80 +0,0 @@ -@extends('layouts.app') - -@section('content') -
-
-
-

Settings

-
- - @if(session('success')) -
- {{ session('success') }} -
- @endif - -
-
-
- @csrf - @method('PUT') - -
-

Article Processing

- -
-
- -

When disabled, the system will not fetch new articles or publish them to platforms.

-
-
- -
-
-
- -
-

Publishing Control

- -
-
- -

When enabled, articles will require manual approval before being published to platforms.

-
-
- -
-
-
- -
- -
-
-
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/partials/navbar.blade.php b/resources/views/partials/navbar.blade.php deleted file mode 100644 index 845964a..0000000 --- a/resources/views/partials/navbar.blade.php +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/resources/views/partials/sidebar.blade.php b/resources/views/partials/sidebar.blade.php deleted file mode 100644 index 28ab1e5..0000000 --- a/resources/views/partials/sidebar.blade.php +++ /dev/null @@ -1,41 +0,0 @@ - diff --git a/run-regression-tests.sh b/run-regression-tests.sh deleted file mode 100755 index d622091..0000000 --- a/run-regression-tests.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/bash - -# FFR Regression Test Suite Runner -# Comprehensive test runner for the FFR application - -set -e - -echo "🧪 Starting FFR Regression Test Suite" -echo "======================================" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Function to print colored output -print_status() { - echo -e "${BLUE}ℹ️ $1${NC}" -} - -print_success() { - echo -e "${GREEN}✅ $1${NC}" -} - -print_warning() { - echo -e "${YELLOW}⚠️ $1${NC}" -} - -print_error() { - echo -e "${RED}❌ $1${NC}" -} - -# Check if we're in the right directory -if [ ! -f "composer.json" ] || [ ! -f "phpunit.xml" ]; then - print_error "This script must be run from the project root directory" - exit 1 -fi - -# Set test environment -export APP_ENV=testing - -print_status "Setting up test environment..." - -# Clear configuration cache -php artisan config:clear --env=testing - -# Ensure database is set up for testing -print_status "Preparing test database..." -php artisan migrate:fresh --env=testing --force - -# Run database seeders for testing if they exist -if [ -f "database/seeders/TestSeeder.php" ]; then - php artisan db:seed --class=TestSeeder --env=testing -fi - -echo "" -print_status "Running regression tests..." -echo "" - -# Track test results -TOTAL_TESTS=0 -FAILED_TESTS=0 - -# Function to run test suite and track results -run_test_suite() { - local suite_name="$1" - local test_path="$2" - local description="$3" - - echo "" - print_status "Running $suite_name..." - echo "Description: $description" - - if php artisan test "$test_path" --env=testing; then - print_success "$suite_name passed" - else - print_error "$suite_name failed" - FAILED_TESTS=$((FAILED_TESTS + 1)) - fi - - TOTAL_TESTS=$((TOTAL_TESTS + 1)) -} - -# Run individual test suites -run_test_suite "API Endpoint Tests" "tests/Feature/ApiEndpointRegressionTest.php" "Tests all HTTP endpoints and routes" - -run_test_suite "Database Integration Tests" "tests/Feature/DatabaseIntegrationTest.php" "Tests models, relationships, and database operations" - -run_test_suite "Article Discovery Tests" "tests/Feature/ArticleDiscoveryCommandTest.php" "Tests article discovery command functionality" - -run_test_suite "Article Publishing Tests" "tests/Feature/ArticlePublishingTest.php" "Tests article publishing workflow" - -run_test_suite "Jobs and Events Tests" "tests/Feature/JobsAndEventsTest.php" "Tests queue jobs and event handling" - -run_test_suite "Authentication & Authorization Tests" "tests/Feature/AuthenticationAndAuthorizationTest.php" "Tests security and access control" - -run_test_suite "New Article Fetched Event Tests" "tests/Feature/NewArticleFetchedEventTest.php" "Tests new article event handling" - -run_test_suite "Validate Article Listener Tests" "tests/Feature/ValidateArticleListenerTest.php" "Tests article validation logic" - -# Run Unit Tests -echo "" -print_status "Running Unit Tests..." - -run_test_suite "Article Fetcher Unit Tests" "tests/Unit/Services/ArticleFetcherTest.php" "Tests article fetching service" - -run_test_suite "Validation Service Unit Tests" "tests/Unit/Services/ValidationServiceTest.php" "Tests article validation service" - -run_test_suite "Dashboard Stats Service Unit Tests" "tests/Unit/Services/DashboardStatsServiceTest.php" "Tests dashboard statistics service" - -# Run full test suite for coverage -echo "" -print_status "Running complete test suite for coverage..." - -if php artisan test --coverage-text --min=70 --env=testing; then - print_success "Test coverage meets minimum requirements" -else - print_warning "Test coverage below 70% - consider adding more tests" -fi - -# Performance Tests -echo "" -print_status "Running performance checks..." - -# Test database query performance -php artisan test tests/Feature/DatabaseIntegrationTest.php --env=testing --stop-on-failure - -# Memory usage test -if php -d memory_limit=128M artisan test --env=testing --stop-on-failure; then - print_success "Memory usage within acceptable limits" -else - print_warning "High memory usage detected during tests" -fi - -# Final Results -echo "" -echo "======================================" -print_status "Test Suite Complete" -echo "======================================" - -if [ $FAILED_TESTS -eq 0 ]; then - print_success "All $TOTAL_TESTS test suites passed! 🎉" - echo "" - echo "Regression test suite completed successfully." - echo "The application is ready for deployment." - exit 0 -else - print_error "$FAILED_TESTS out of $TOTAL_TESTS test suites failed" - echo "" - echo "Please review the failing tests before proceeding." - echo "Run individual test suites with:" - echo " php artisan test tests/Feature/[TestFile].php" - echo " php artisan test tests/Unit/[TestFile].php" - exit 1 -fi \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index f905a3e..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "ESNext" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - "noEmit": true /* Disable emitting files from a compilation. */, - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - - /* Interop Constraints */ - "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */, - "baseUrl": ".", - "paths": { - "@/*": ["./resources/js/*"], - "ziggy-js": ["./vendor/tightenco/ziggy"] - }, - "jsx": "react-jsx" - }, - "include": [ - "resources/js/**/*.ts", - "resources/js/**/*.d.ts", - "resources/js/**/*.tsx", - ] -} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 7393f61..0000000 --- a/vite.config.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { defineConfig } from 'vite'; -import laravel from 'laravel-vite-plugin'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [ - react(), - laravel({ - input: [ - 'resources/css/app.css', - 'resources/js/app.tsx', - ], - refresh: true, - }), - ], - server: { - host: '0.0.0.0', - port: 5173, - hmr: { - host: 'localhost', - }, - watch: { - usePolling: true, - interval: 1000, - }, - }, - esbuild: { - target: 'es2020', - jsx: 'automatic', - }, - resolve: { - extensions: ['.tsx', '.ts', '.jsx', '.js'], - }, - optimizeDeps: { - include: ['react', 'react-dom'], - esbuildOptions: { - target: 'es2020', - jsx: 'automatic', - }, - }, -}); \ No newline at end of file