Compare commits

...

49 Commits

Author SHA1 Message Date
bc56a1824f Add Filament Spatie Laravel Translatable Plugin and update dependencies in composer files
- Added the `filament/spatie-laravel-translatable-plugin` to `composer.json` for enhanced localization support.
- Updated `composer.lock` to reflect the addition of the new plugin and updated versions for several dependencies, including `doctrine/dbal`, `phpstan/phpstan`, and `phpunit/phpunit`.
- Modified `PanelPanelProvider.php` to integrate the translatable plugin with default locales for improved internationalization.
2025-07-29 18:30:32 +05:00
6405150dd2 Remove language files for English, Russian, and Turkmen, streamlining localization resources as part of the ongoing internationalization efforts. 2025-07-29 18:24:17 +05:00
1a3f82b22c Implement language switcher functionality and enhance localization support: add available locales configuration, update SetLocale middleware to handle language selection via query parameters, and integrate language switcher buttons in the settings layout. Additionally, update various views to utilize translation functions for improved internationalization, ensuring consistent language support across the application. 2025-07-29 17:04:13 +05:00
0b6cbc8d9e ok 2025-07-29 16:44:00 +05:00
834822e182 Remove welcome.blade.php and update various views to use translation functions for improved localization support. Changes include updating labels, titles, and alerts across multiple pages to utilize the __('') function, enhancing the application's internationalization capabilities. 2025-07-29 16:39:27 +05:00
e927a912e1 lang 2025-07-29 16:17:32 +05:00
643ccd6d9e Add role-based access control to various settings pages: implement canAccess method in AboutPageSettings, ContactPageSettings, HomePageSettings, ManageCtaSettings, ManagePortfolio, ManageSite, ManageSiteSocialSettings, ManageSolutions, ManageSuccess, and update User model to include canManageSettings method for enhanced security and user experience. 2025-07-29 15:54:16 +05:00
3e80ea4d5e Update .gitignore to include IntelephenseHelper.php, ensuring proper file management and preventing unnecessary tracking of this file. 2025-07-29 15:45:42 +05:00
fe42967a74 Add role-based access control to management pages: implement canView method in ManageCtaSettings, ManagePortfolio, ManageSolutions, and ManageSuccess classes to restrict access to ADMIN and MANAGER roles, enhancing security and user experience. 2025-07-29 15:45:22 +05:00
a1826ae53c Add user role management: introduce UserRole enum for role definitions, implement role-based access control in various resources and pages, and enhance authorization logic in the PanelProvider for improved security and user experience. 2025-07-29 15:33:36 +05:00
c7e01f404d Update navigation groups for various resources: change navigation group names for AboutPageSettings, ContactPageSettings, AuthorResource, BrandResource, CommentResource, InternshipResource, NewsResource, SolutionResource, SuccessResource, and TeamMemberResource to better reflect their content. Enhance panel navigation structure by adding new groups for improved organization. 2025-07-29 15:14:36 +05:00
0a3fdf347f Add downloads and FAQs functionality to SolutionResource: implement repeaters for downloads and FAQs in the form, update Solution model to include new fields, and enhance the show view to display downloads and FAQs dynamically, improving content management and user experience. 2025-07-29 14:54:13 +05:00
e97a80bfdb Enhance SolutionResource form functionality: add debounce to slug generation for improved user experience during input, and adjust layout in show.blade.php by reducing column width for better content presentation. 2025-07-29 14:48:23 +05:00
dd167d9aaa Enhance pricing section layout: update _pricing.scss to use flexbox for better alignment and spacing. Modify breadcrumb links in show.blade.php for correct asset paths and simplify the layout by removing the sidebar, allowing for a more streamlined content presentation. 2025-07-29 14:41:26 +05:00
8f36f7d715 wip 2025-07-29 14:31:47 +05:00
453e8caa82 Refactor About page settings: replace management section with a video upload feature, update view to display static management information, and clean up related settings for improved content management and user experience. 2025-07-29 14:28:03 +05:00
76397637f0 Integrate dynamic settings into About page: update content sections to utilize AboutSettings for titles, subtitles, paragraphs, and media sources, enhancing content management and user experience. 2025-07-29 14:16:10 +05:00
8e770941fa Refactor resource files: remove unused imports and clean up code across various resource and controller files for improved readability and maintainability. Update currency list formatting in helpers for consistency. 2025-07-29 13:29:23 +05:00
c37f5fadf1 Add contact settings integration: update contact page to utilize dynamic settings for subtitle, header, paragraph, contact details, and map embed URL, enhancing content management and user experience. 2025-07-29 13:22:44 +05:00
287fbf55f9 wip 2025-07-29 13:04:14 +05:00
3ca39597a2 Add section title and description to success stories page for improved user engagement and context. 2025-07-29 12:59:14 +05:00
affe615592 Remove image display from news and success pages to streamline content presentation. 2025-07-29 12:57:50 +05:00
c1770cafa5 Refactor blog item display: update styles for blog items, enhance news and success pages to handle empty states with informative messages, and adjust author image path for consistency. 2025-07-29 12:56:26 +05:00
d4403ce365 Update NewsResource to route index page to ManageNews instead of ListNews for improved resource management. 2025-07-29 12:47:44 +05:00
b9bc8fbcee Rename ListNews class to ManageNews in ManageNews.php for improved clarity and consistency in resource management. 2025-07-29 12:46:49 +05:00
f6ddf1d9c1 Enhance internship application process: update InternshipsPageController to retrieve internships and validate application submissions, modify Internship model to include relationships, and implement dynamic application modals in views for internships and careers. Update Livewire configuration for improved file upload handling. 2025-07-29 12:37:25 +05:00
9603402fee Update careers index view to include salary currency options and enhance form validation for improved user experience. 2025-07-29 12:09:06 +05:00
1f8888d31c Remove max size limit for background video upload in HomePageSettings and add ApplicationResource to the panel resources in PanelPanelProvider. 2025-07-29 12:00:19 +05:00
330fc76ed3 Refactor application submission response in ApplicationController to return JSON format and update phone number validation rule. Modify careers index view to handle new response structure. 2025-07-29 11:38:42 +05:00
a627c85416 Add CSRF token meta tag for enhanced security and update form labels in careers index view to indicate required fields. 2025-07-29 11:30:14 +05:00
f9f08c7adf Add salary currency field to Career resource and model, implement currency options, and update careers index view 2025-07-29 11:08:20 +05:00
8a2166bd78 wip 2025-07-29 00:27:48 +05:00
a89e2a71d8 Enhance careers management features: update CareersPageController to fetch and display career listings with additional fields, modify Career model to include relationships and new attributes, and create a new view for the careers index with an application modal. Update database migration to reflect changes in the careers table structure and adjust routes for application submissions. 2025-07-29 00:23:08 +05:00
9b3ca3ff66 Update footer and header navigation links to reflect new route for success stories, and remove pagination section from news index view for cleaner layout. 2025-07-28 21:17:54 +05:00
41abdb6fc8 Update news index view: change page title from 'Blog 3 Columns' to 'News' and adjust breadcrumb navigation for improved clarity and consistency. 2025-07-28 21:07:27 +05:00
6b0c92d838 Refactor News management features: replace author text input with a searchable select component in NewsResource, update NewsPageController to fetch news with authors and recent articles, and enhance the news show view to display author details and comments more effectively. 2025-07-28 21:05:24 +05:00
1b4989b440 Enhance solution management features: add title_description and bullets fields to SolutionResource, update OurSolutionPageController to fetch solutions in descending order, and create new views for displaying solutions with detailed descriptions and bullet points. Adjust CSS for active button styling and update navigation to reflect title instead of name for solutions. 2025-07-28 20:33:38 +05:00
e2323c7949 Refactor file imports and clean up unused components in various resources: remove unnecessary imports in CommentResource, NewsResource, and SolutionResource, and ensure consistent formatting across files. Add missing newlines at the end of files for better code quality. 2025-07-28 20:10:34 +05:00
b23f537086 Update navigation groups for various resources: change ManageCtaSettings to 'Home', CommentResource and NewsResource to 'News', and add 'Brands' for BrandResource. Update navigation icon for SolutionResource to 'heroicon-o-light-bulb'. 2025-07-28 20:08:37 +05:00
7fdb99cc79 Refactor navigation settings across multiple pages: update navigation groups and labels for HomePageSettings, ManageCtaSettings, ManagePortfolio, ManageSolutions, ManageSuccess, and ManageSite. Introduce solutions data fetching in OurSolutionPageController and enhance header navigation with dynamic solutions list. Update database migration to include new fields for solutions. 2025-07-28 20:06:11 +05:00
74fc3b5e6a Implement news management features: add author field and comments functionality in NewsResource, enhance HomePageController to fetch latest news, and create dedicated views for news display and commenting. Update routes for comment submission and adjust homepage to showcase recent news articles. 2025-07-28 18:56:17 +05:00
189cb53856 Enhance ManageSolutions and ManageSuccess forms: replace icon_class text input with a searchable select component in ManageSolutions, add file upload for success images in ManageSuccess, and update SuccessSettings to include success_image property. Adjust related database migrations and views for dynamic content display. 2025-07-28 18:28:29 +05:00
d316f392bc Update HomePageSettings to use file upload for background video: replace text input with FileUpload component, enforce file type and size restrictions, and adjust video source path in the homepage view for proper video display. 2025-07-28 18:10:07 +05:00
2d1c7ea4f9 Add solutions image upload field and update settings: introduce a file upload component for solutions images in ManageSolutions, add solutions_image property to SolutionSettings, and update related database migrations and views to support dynamic image display. 2025-07-28 17:43:05 +05:00
bae4204d44 Refactor form components across multiple pages: enforce required validation on various text inputs and file uploads in HomePageSettings, ManagePortfolio, ManageSite, ManageSiteSocialSettings, ManageSolutions, ManageSuccess, and update the news index view to display dynamic content. 2025-07-28 17:14:40 +05:00
1ceccb0d79 Update HomePageSettings to require additional fields: enforce required validation on various text inputs and file uploads for better data integrity. 2025-07-28 16:40:58 +05:00
ed369a5bf2 Add industry and text slide sections to homepage settings: introduce new fields in HomeSettings, update form structure in HomePageSettings, and modify homepage view to display dynamic content for industry and text slide areas. 2025-07-28 16:15:46 +05:00
6d564bb285 Enhance homepage with dynamic success and portfolio settings: replace static content with values from SuccessSettings and PortfolioSettings, and implement loops for skill and portfolio items. 2025-07-28 15:18:32 +05:00
fb4479929d Integrate dynamic solution settings into homepage: replace static service titles and button with values from SolutionSettings, and implement a loop to display service items dynamically. 2025-07-28 13:18:25 +05:00
154 changed files with 6928 additions and 1292 deletions

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@ yarn-error.log
/.vscode
/.zed
**/.DS_Store
IntelephenseHelper.php

View File

@@ -0,0 +1,259 @@
<?php
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\AboutSettings;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
use Illuminate\Contracts\Support\Htmlable;
class AboutPageSettings extends SettingsPage
{
protected static ?string $navigationGroup = 'CMS';
protected static ?string $navigationIcon = 'heroicon-o-information-circle';
protected static string $settings = AboutSettings::class;
public function form(Form $form): Form
{
return $form
->schema([
Section::make('Our Story Section')
->description("Manage the 'Our Story' content on the About Us page.")
->icon('heroicon-o-book-open')
->schema([
TextInput::make('our_story_title')
->label('Title')
->required()
->maxLength(100),
Textarea::make('our_story_subtitle')
->label('Subtitle')
->rows(2)
->maxLength(255)
->required(),
Textarea::make('our_story_paragraph_one')
->label('Paragraph One')
->rows(4)
->maxLength(65535)
->required(),
Textarea::make('our_story_paragraph_two')
->label('Paragraph Two')
->rows(4)
->maxLength(65535)
->required(),
Textarea::make('our_story_paragraph_three')
->label('Paragraph Three')
->rows(4)
->maxLength(65535)
->required(),
Grid::make(2)->schema([
TextInput::make('our_story_button_text')
->label('Button Text')
->maxLength(50)
->required(),
TextInput::make('our_story_button_url')
->label('Button URL')
->url()
->maxLength(255)
->required(),
]),
FileUpload::make('our_story_video_poster')
->label('Video Poster Image')
->image()
->maxSize(2048)
->disk('public')
->directory('about-us')
->required(),
FileUpload::make('our_story_video_source')
->label('Video Source File')
->acceptedFileTypes(['video/mp4', 'video/webm', 'video/ogg'])
->maxSize(102400) // 100MB
->disk('public')
->directory('about-us-videos')
->required(),
]),
Section::make('Our Journey Section')
->description("Manage the 'Our Journey' milestones on the About Us page.")
->icon('heroicon-o-map')
->schema([
TextInput::make('our_journey_title')
->label('Title')
->required()
->maxLength(100),
Textarea::make('our_journey_subtitle')
->label('Subtitle')
->rows(2)
->maxLength(255)
->required(),
Repeater::make('our_journey_milestones')
->label('Milestones')
->schema([
TextInput::make('year')
->label('Year')
->numeric()
->required(),
TextInput::make('title')
->label('Milestone Title')
->required()
->maxLength(100),
Textarea::make('description')
->label('Description')
->rows(3)
->maxLength(255)
->required(),
FileUpload::make('image')
->label('Image')
->image()
->maxSize(2048)
->disk('public')
->directory('about-us-milestones')
->required(),
])
->minItems(1)
->columns(1)
->reorderable()
->collapsible(),
]),
Section::make('Company Structure Section')
->description("Manage the 'Company Structure' details on the About Us page.")
->icon('heroicon-o-user-group')
->schema([
TextInput::make('company_structure_title')
->label('Title')
->required()
->maxLength(100),
Textarea::make('company_structure_subtitle')
->label('Subtitle')
->rows(2)
->maxLength(255)
->required(),
TextInput::make('company_structure_director_name')
->label('Director Name')
->required()
->maxLength(100),
TextInput::make('company_structure_advisor_name')
->label('Technical Advisor Name')
->required()
->maxLength(100),
Repeater::make('company_structure_departments')
->label('Departments')
->schema([
TextInput::make('name')
->label('Department Name')
->required()
->maxLength(100),
TextInput::make('person')
->label('Contact Person')
->required()
->maxLength(100),
])
->minItems(1)
->columns(2)
->reorderable()
->collapsible(),
]),
Section::make('Our Facilities Section')
->description("Manage the 'Our Facilities' details on the About Us page.")
->icon('heroicon-o-building-library')
->schema([
TextInput::make('our_facilities_title')
->label('Title')
->required()
->maxLength(100),
Textarea::make('our_facilities_subtitle')
->label('Subtitle')
->rows(2)
->maxLength(255)
->required(),
Repeater::make('our_facilities_locations')
->label('Locations')
->schema([
FileUpload::make('image')
->label('Image')
->image()
->maxSize(2048)
->disk('public')
->directory('about-us-facilities')
->required(),
TextInput::make('name')
->label('Location Name')
->required()
->maxLength(100),
TextInput::make('location')
->label('Address/Location')
->required()
->maxLength(255),
Textarea::make('description')
->label('Description')
->rows(3)
->maxLength(255)
->required(),
Repeater::make('tags')
->label('Tags')
->simple(TextInput::make('value')
->label('Tag')
->required()
->maxLength(50))
->itemLabel(fn (array $state): ?string => $state['value'] ?? null)
->minItems(1)
->columns(1)
->reorderable()
->collapsible()
->defaultItems(1),
])
->minItems(1)
->columns(1)
->reorderable()
->collapsible(),
]),
])
->columns(1)
->statePath('data');
}
public static function getNavigationGroup(): ?string
{
return __('About US');
}
public static function getNavigationLabel(): string
{
return __('About Page Settings');
}
public function getTitle(): string|Htmlable
{
return 'About Us';
}
public function getHeading(): string|Htmlable
{
return 'Edit About Us page text and images from here';
}
public function getSubheading(): string|Htmlable|null
{
return 'Manage the content sections of the About Us page.';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\ContactSettings;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
use Illuminate\Contracts\Support\Htmlable;
class ContactPageSettings extends SettingsPage
{
protected static ?string $navigationGroup = 'Contact';
protected static ?string $navigationIcon = 'heroicon-o-phone';
protected static string $settings = ContactSettings::class;
public function form(Form $form): Form
{
return $form
->schema([
Section::make('Contact Section')
->description('Manage the contact page content.')
->schema([
TextInput::make('contact_subtitle')
->label('Subtitle')
->maxLength(100)
->required(),
TextInput::make('contact_header')
->label('Header')
->maxLength(100)
->required(),
Textarea::make('contact_paragraph')
->label('Paragraph')
->rows(3)
->maxLength(65535)
->required(),
TextInput::make('phone_number')
->label('Phone Number')
->tel()
->required(),
TextInput::make('email_address')
->label('Email Address')
->email()
->required(),
TextInput::make('location_address')
->label('Location Address')
->maxLength(255)
->required(),
TextInput::make('map_embed_url')
->label('Google Maps Embed URL')
->url()
->required(),
]),
])
->columns(1)
->statePath('data');
}
public static function getNavigationGroup(): ?string
{
return __('Contact');
}
public static function getNavigationLabel(): string
{
return __('Contact Page Settings');
}
public function getTitle(): string|Htmlable
{
return 'Contact Page';
}
public function getHeading(): string|Htmlable
{
return 'Edit contact page text and information from here';
}
public function getSubheading(): string|Htmlable|null
{
return 'Manage the contact form details, contact information, and map embed.';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -2,19 +2,22 @@
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\HomeSettings;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Pages\SettingsPage;
use Illuminate\Contracts\Support\Htmlable;
class HomePageSettings extends SettingsPage
{
protected static ?string $navigationGroup = 'Home';
protected static ?string $navigationIcon = 'heroicon-o-home';
protected static string $settings = HomeSettings::class;
@@ -29,7 +32,8 @@ class HomePageSettings extends SettingsPage
->schema([
TextInput::make('hero_badge_text')
->label('Hero Badge Text')
->maxLength(50),
->maxLength(50)
->required(),
TextInput::make('hero_header')
->label('Hero Header')
->required()
@@ -37,15 +41,18 @@ class HomePageSettings extends SettingsPage
Textarea::make('hero_sub_header')
->label('Hero Sub Header')
->rows(3)
->maxLength(255),
->maxLength(255)
->required(),
Grid::make()->schema([
TextInput::make('hero_link_button_text')
->label('Hero Button Text')
->maxLength(50),
->maxLength(50)
->required(),
TextInput::make('hero_link_button_url')
->label('Hero Button URL')
->maxLength(255)
->url(),
->url()
->required(),
])->columns(2),
]),
@@ -55,7 +62,8 @@ class HomePageSettings extends SettingsPage
->schema([
TextInput::make('about_subtitle')
->label('About Subtitle')
->maxLength(100),
->maxLength(100)
->required(),
TextInput::make('about_header')
->label('About Header')
->required()
@@ -63,46 +71,55 @@ class HomePageSettings extends SettingsPage
Textarea::make('about_paragraph')
->label('About Paragraph')
->rows(5)
->maxLength(65535),
->maxLength(65535)
->required(),
Grid::make()->schema([
TextInput::make('about_projects_text')
->label('Projects Text')
->maxLength(100),
->maxLength(100)
->required(),
TextInput::make('about_projects_number')
->label('Projects Number')
->numeric(),
->numeric()
->required(),
])->columns(2),
Grid::make()->schema([
TextInput::make('about_members_text')
->label('Members Text')
->maxLength(100),
->maxLength(100)
->required(),
TextInput::make('about_members_number')
->label('Members Number')
->numeric(),
->numeric()
->required(),
])->columns(2),
Grid::make()->schema([
TextInput::make('about_reviews_text')
->label('Reviews Text')
->maxLength(100),
->maxLength(100)
->required(),
TextInput::make('about_reviews_number')
->label('Reviews Number')
->numeric(),
->numeric()
->required(),
])->columns(2),
Grid::make()->schema([
TextInput::make('about_button_text')
->label('About Button Text')
->maxLength(50),
->maxLength(50)
->required(),
TextInput::make('about_button_url')
->label('About Button URL')
->maxLength(255)
->url(),
->url()
->required(),
])->columns(2),
Grid::make()->schema([
@@ -111,13 +128,15 @@ class HomePageSettings extends SettingsPage
->image()
->maxSize(2048)
->disk('public')
->directory('about-images'),
->directory('about-images')
->required(),
FileUpload::make('about_image_two')
->label('About Image Two (375x391)')
->image()
->maxSize(2048)
->disk('public')
->directory('about-images'),
->directory('about-images')
->required(),
])->columns(2),
]),
@@ -125,10 +144,125 @@ class HomePageSettings extends SettingsPage
->description('Upload or link the background video for the hero section.')
->icon('heroicon-o-camera')
->schema([
TextInput::make('bg_video')
->label('Background Video URL')
->maxLength(255)
->url(),
FileUpload::make('bg_video')
->label('Background Video')
->acceptedFileTypes(['video/mp4', 'video/webm', 'video/ogg'])
->disk('public')
->directory('homepage-videos')
->required(),
]),
Section::make('Industry Area')
->description('Manage the content for the industry area section.')
->icon('heroicon-o-building-office')
->schema([
TextInput::make('industry_subtitle')
->label('Subtitle')
->maxLength(100)
->required(),
TextInput::make('industry_header')
->label('Header')
->required()
->maxLength(255),
Textarea::make('industry_paragraph')
->label('Paragraph')
->rows(3)
->maxLength(65535)
->required(),
Grid::make()->schema([
TextInput::make('industry_button_text')
->label('Button Text')
->maxLength(50)
->required(),
TextInput::make('industry_button_url')
->label('Button URL')
->maxLength(255)
->url()
->required(),
])->columns(2),
FileUpload::make('industry_image_one')
->label('Industry Image One (520x400)')
->image()
->maxSize(2048)
->disk('public')
->directory('industry-images')
->required(),
Repeater::make('industry_items')
->label('Industry Items')
->schema([
FileUpload::make('icon')
->label('Icon (SVG)')
->directory('industry-icons')
->acceptedFileTypes(['image/svg+xml'])
->maxSize(1024) // 1MB
->required(),
TextInput::make('title')
->label('Title')
->required()
->maxLength(100),
Textarea::make('description')
->label('Description')
->rows(2)
->maxLength(255)
->required(),
])
->columns(2)
->minItems(1)
->maxItems(5)
->defaultItems(2)
->reorderable()
->collapsible(),
]),
Section::make('Text Slide Area')
->description('Manage the content for the text slide area section.')
->icon('heroicon-o-chat-bubble-bottom-center-text')
->schema([
TextInput::make('text_slide_subtitle')
->label('Subtitle')
->maxLength(100)
->required(),
TextInput::make('text_slide_header')
->label('Header')
->required()
->maxLength(255),
FileUpload::make('text_slide_image')
->label('Text Slide Image (540x350)')
->image()
->maxSize(2048)
->disk('public')
->directory('text-slide-images')
->required(),
TextInput::make('text_slide_counter_number')
->label('Counter Number')
->numeric()
->default(29)
->required(),
Repeater::make('text_slide_items')
->label('Text Slide Items')
->schema([
FileUpload::make('icon')
->label('Icon (SVG)')
->directory('text-slide-icons')
->acceptedFileTypes(['image/svg+xml'])
->maxSize(1024) // 1MB
->required(),
TextInput::make('link')
->label('Link')
->required()
->url()
->maxLength(255),
TextInput::make('text')
->label('Text')
->required()
->maxLength(100),
])
->columns(3)
->minItems(1)
->maxItems(10)
->defaultItems(6)
->reorderable()
->collapsible(),
]),
])
->columns(1)
@@ -137,12 +271,12 @@ class HomePageSettings extends SettingsPage
public static function getNavigationGroup(): ?string
{
return __('CMS');
return __('Home');
}
public static function getNavigationLabel(): string
{
return __('Home');
return __('Home Page Settings');
}
public function getTitle(): string|Htmlable
@@ -159,4 +293,14 @@ class HomePageSettings extends SettingsPage
{
return 'Manage the homepage hero section, background video, and call-to-action content.';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\CtaSettings;
use Filament\Forms;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
class ManageCtaSettings extends SettingsPage
{
protected static ?string $navigationGroup = 'Home';
protected static ?string $navigationIcon = 'heroicon-o-megaphone';
protected static string $settings = CtaSettings::class;
public static function getNavigationLabel(): string
{
return 'Call To Action';
}
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('title')
->label('Call To Action Title')
->required(),
Forms\Components\TextInput::make('button_text')
->label('Button Text')
->required(),
Forms\Components\TextInput::make('button_url')
->label('Button URL')
->required()
->url(),
FileUpload::make('background_image')
->label('Background Image 1320x408')
->directory('settings')
->image()
->columnSpan('full'),
]);
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\PortfolioSettings;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
use Illuminate\Contracts\Support\Htmlable;
class ManagePortfolio extends SettingsPage
{
protected static ?string $navigationGroup = 'Home';
protected static ?string $navigationIcon = 'heroicon-o-briefcase';
protected static string $settings = PortfolioSettings::class;
public function form(Form $form): Form
{
return $form
->schema([
Section::make('Portfolio Section Content')
->description('Manage the main content for the portfolio section.')
->icon('heroicon-o-document-text')
->schema([
TextInput::make('portfolio_header')
->label('Header')
->required()
->maxLength(255),
Grid::make()->schema([
TextInput::make('portfolio_button_text')
->label('Button Text')
->required()
->maxLength(50),
TextInput::make('portfolio_button_url')
->label('Button URL')
->required()
->maxLength(255)
->url(),
])->columns(2),
]),
Section::make('Portfolio Items')
->description('Manage individual portfolio items.')
->icon('heroicon-o-photo')
->schema([
Repeater::make('portfolio_items')
->label('Portfolio Items')
->schema([
FileUpload::make('image')
->label('Image (700x525)')
->image()
->maxSize(2048)
->disk('public')
->directory('portfolio-images')
->required(),
TextInput::make('category')
->label('Category')
->required()
->maxLength(100),
TextInput::make('title')
->label('Title')
->required()
->maxLength(255),
TextInput::make('link')
->label('Link')
->required()
->maxLength(255)
->url(),
])
->columns(2)
->minItems(1)
->maxItems(8)
->defaultItems(4)
->reorderable()
->collapsible(),
]),
])
->columns(1)
->statePath('data');
}
public static function getNavigationGroup(): ?string
{
return __('Home');
}
public static function getNavigationLabel(): string
{
return __('Portfolio');
}
public function getTitle(): string|Htmlable
{
return 'Portfolio';
}
public function getHeading(): string|Htmlable
{
return 'Edit portfolio section content from here';
}
public function getSubheading(): string|Htmlable|null
{
return 'Manage the portfolio section content, including items, categories, and titles.';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\SiteSettings;
use Filament\Forms;
use Filament\Forms\Form;
@@ -10,6 +11,8 @@ use Illuminate\Contracts\Support\Htmlable;
class ManageSite extends SettingsPage
{
protected static ?string $navigationGroup = 'Settings';
protected static ?string $navigationIcon = 'heroicon-o-globe-alt';
protected static string $settings = SiteSettings::class;
@@ -38,10 +41,12 @@ class ManageSite extends SettingsPage
->maxLength(100),
Forms\Components\TextInput::make('tagline')
->label('Site Tagline')
->required()
->helperText('A short phrase describing your site')
->maxLength(150),
Forms\Components\Textarea::make('description')
->label('Site Description')
->required()
->helperText('A detailed description of your website')
->rows(3)
->maxLength(500),
@@ -65,13 +70,16 @@ class ManageSite extends SettingsPage
->maxLength(100),
Forms\Components\TextInput::make('company_phone')
->label('Company Phone')
->required()
->maxLength(20),
Forms\Components\TextInput::make('company_phone_2')
->label('Company Additional Phone')
->required()
->maxLength(20),
])->columns(2),
Forms\Components\Textarea::make('company_address')
->label('Company Address')
->required()
->rows(2)
->maxLength(200),
]),
@@ -94,17 +102,20 @@ class ManageSite extends SettingsPage
->schema([
Forms\Components\TextInput::make('copyright_text')
->label('Copyright Text')
->required()
->maxLength(200),
Forms\Components\Grid::make()->schema([
Forms\Components\TextInput::make('terms_url')
->label('Terms & Conditions URL')
->required()
->maxLength(100)
->prefix(function (Forms\Get $get) {
return url('/');
}),
Forms\Components\TextInput::make('privacy_url')
->label('Privacy Policy URL')
->required()
->maxLength(100)
->prefix(function (Forms\Get $get) {
return url('/');
@@ -120,10 +131,12 @@ class ManageSite extends SettingsPage
Forms\Components\Grid::make()->schema([
Forms\Components\Textarea::make('custom_404_message')
->label('404 Not Found Message')
->required()
->rows(2)
->maxLength(500),
Forms\Components\Textarea::make('custom_500_message')
->label('500 Server Error Message')
->required()
->rows(2)
->maxLength(500),
])->columns(2),
@@ -156,4 +169,14 @@ class ManageSite extends SettingsPage
{
return 'Manage your website\'s general configuration';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\SiteSocialSettings;
use Filament\Forms;
use Filament\Forms\Form;
@@ -10,7 +11,7 @@ use Illuminate\Contracts\Support\Htmlable;
class ManageSiteSocialSettings extends SettingsPage
{
protected static ?int $navigationSort = 4;
protected static ?string $navigationGroup = 'Settings';
protected static ?string $navigationIcon = 'heroicon-o-share';
@@ -28,18 +29,22 @@ class ManageSiteSocialSettings extends SettingsPage
Forms\Components\Grid::make()->schema([
Forms\Components\TextInput::make('facebook_url')
->label('Facebook URL')
->required()
->prefix('https://')
->helperText('e.g., facebook.com/yourpage'),
Forms\Components\TextInput::make('twitter_url')
->label('Twitter/X URL')
->required()
->prefix('https://')
->helperText('e.g., twitter.com/yourusername'),
Forms\Components\TextInput::make('instagram_url')
->label('Instagram URL')
->required()
->prefix('https://')
->helperText('e.g., instagram.com/yourusername'),
Forms\Components\TextInput::make('linkedin_url')
->label('LinkedIn URL')
->required()
->prefix('https://')
->helperText('e.g., linkedin.com/company/yourcompany'),
])->columns(2),
@@ -73,4 +78,14 @@ class ManageSiteSocialSettings extends SettingsPage
{
return 'Manage your social media profiles and sharing options';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,390 @@
<?php
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\SolutionSettings;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
use Illuminate\Contracts\Support\Htmlable;
class ManageSolutions extends SettingsPage
{
protected static ?string $navigationGroup = 'Home';
protected static ?string $navigationIcon = 'heroicon-o-wrench-screwdriver';
protected static string $settings = SolutionSettings::class;
public function form(Form $form): Form
{
return $form
->schema([
Section::make('Solutions Section')
->description('Manage the content for the solutions section on the homepage.')
->icon('heroicon-o-puzzle-piece')
->schema([
TextInput::make('solutions_subtitle')
->label('Subtitle')
->required()
->maxLength(100),
TextInput::make('solutions_header')
->label('Header')
->required()
->maxLength(255),
FileUpload::make('solutions_image')
->label('Image 1060x453')
->image()
->directory('solutions')
->required(),
Grid::make()->schema([
TextInput::make('solutions_button_text')
->label('Button Text')
->required()
->maxLength(50),
TextInput::make('solutions_button_url')
->label('Button URL')
->required()
->maxLength(255)
->url(),
])->columns(2),
]),
Section::make('Solution Items')
->description('Manage individual solution items.')
->icon('heroicon-o-cube')
->schema([
Repeater::make('solution_items')
->label('Solution Items')
->schema([
Select::make('icon_class')
->label('Icon Class')
->searchable()
->helperText('e.g., flaticon-it-department. Refer to Flaticon for available icons.')
->required()
->options(self::getIconOptions()),
TextInput::make('title')
->label('Title')
->required()
->maxLength(100),
TextInput::make('link')
->label('Link')
->required()
->maxLength(255)
->url(),
])
->columns(3)
->minItems(1)
->maxItems(6)
->defaultItems(3)
->grid(2)
->reorderable()
->collapsible(),
]),
])
->columns(1)
->statePath('data');
}
private static function getIconOptions(): array
{
return [
'microsoft-word' => 'microsoft-word',
'text-box' => 'text-box',
'document-1' => 'document-1',
'layers-1' => 'layers-1',
'folder-1' => 'folder-1',
'contract' => 'contract',
'layer' => 'layer',
'download-pdf' => 'download-pdf',
'pdf' => 'pdf',
'cloud-computing' => 'cloud-computing',
'downloads' => 'downloads',
'layers' => 'layers',
'document' => 'document',
'light-bulb-1' => 'light-bulb-1',
'idea-2' => 'idea-2',
'light-bulb' => 'light-bulb',
'idea-1' => 'idea-1',
'solution-2' => 'solution-2',
'lightbulb' => 'lightbulb',
'menus' => 'menus',
'support-1' => 'support-1',
'swipe-left' => 'swipe-left',
'development' => 'development',
'domain' => 'domain',
'pets' => 'pets',
'diagram' => 'diagram',
'targeting' => 'targeting',
'business-intelligence' => 'business-intelligence',
'menu-6' => 'menu-6',
'high-quality' => 'high-quality',
'campaign' => 'campaign',
'brain' => 'brain',
'software-application' => 'software-application',
'apps' => 'apps',
'wrench-1' => 'wrench-1',
'social-media-marketing-1' => 'social-media-marketing-1',
'category-1' => 'category-1',
'trophy-3' => 'trophy-3',
'email-marketing' => 'email-marketing',
'setting' => 'setting',
'more' => 'more',
'menu-5' => 'menu-5',
'menu-4' => 'menu-4',
'medical' => 'medical',
'sparkle' => 'sparkle',
'menu-3' => 'menu-3',
'technology-2' => 'technology-2',
'process' => 'process',
'hearth-1' => 'hearth-1',
'hearth' => 'hearth',
'technology-1' => 'technology-1',
'category' => 'category',
'customer-care' => 'customer-care',
'folder' => 'folder',
'portfolio-1' => 'portfolio-1',
'report' => 'report',
'thinking' => 'thinking',
'fingerprint' => 'fingerprint',
'clock-2' => 'clock-2',
'award' => 'award',
'paper-plane' => 'paper-plane',
'repair' => 'repair',
'email-5' => 'email-5',
'strategy' => 'strategy',
'portfolio' => 'portfolio',
'web-design' => 'web-design',
'email-4' => 'email-4',
'down-arrow-1' => 'down-arrow-1',
'location-2' => 'location-2',
'phone-call-2' => 'phone-call-2',
'telephone-call' => 'telephone-call',
'teamwork' => 'teamwork',
'up-arrow-1' => 'up-arrow-1',
'menu-2' => 'menu-2',
'developing' => 'developing',
'money-bag' => 'money-bag',
'thumbs-up' => 'thumbs-up',
'profits' => 'profits',
'location-1' => 'location-1',
'help-1' => 'help-1',
'online-chat' => 'online-chat',
'worker' => 'worker',
'smart-home' => 'smart-home',
'customer-service-1' => 'customer-service-1',
'internet' => 'internet',
'cash-flow' => 'cash-flow',
'monitor' => 'monitor',
'search-1' => 'search-1',
'wrench' => 'wrench',
'coin' => 'coin',
'cash' => 'cash',
'analyst' => 'analyst',
'dashboard-1' => 'dashboard-1',
'digital' => 'digital',
'searching' => 'searching',
'email-3' => 'email-3',
'star-1' => 'star-1',
'touch' => 'touch',
'medal' => 'medal',
'world-wide-web-1' => 'world-wide-web-1',
'phone' => 'phone',
'social-media' => 'social-media',
'24-7' => '24-7',
'hard-work' => 'hard-work',
'star' => 'star',
'plus' => 'plus',
'minus-2' => 'minus-2',
'menu-1' => 'menu-1',
'cloud' => 'cloud',
'handshake' => 'handshake',
'people' => 'people',
'ai' => 'ai',
'save-money' => 'save-money',
'shopping-online' => 'shopping-online',
'profit-1' => 'profit-1',
'blockchain' => 'blockchain',
'sales' => 'sales',
'back-in-time' => 'back-in-time',
'clock-1' => 'clock-1',
'user-3' => 'user-3',
'user-2' => 'user-2',
'pawprint' => 'pawprint',
'payment-method' => 'payment-method',
'world-wide-web' => 'world-wide-web',
'minus-1' => 'minus-1',
'add-1' => 'add-1',
'management' => 'management',
'help' => 'help',
'chip' => 'chip',
'artificial-intelligence' => 'artificial-intelligence',
'group' => 'group',
'money-1' => 'money-1',
'conversation' => 'conversation',
'email-2' => 'email-2',
'rating' => 'rating',
'placeholder' => 'placeholder',
'trophy-2' => 'trophy-2',
'cpu' => 'cpu',
'home' => 'home',
'right-arrow-1' => 'right-arrow-1',
'like' => 'like',
'mail' => 'mail',
'briefcase' => 'briefcase',
'money' => 'money',
'up-arrow' => 'up-arrow',
'trophy-1' => 'trophy-1',
'user-1' => 'user-1',
'question' => 'question',
'team-1' => 'team-1',
'user' => 'user',
'email-1' => 'email-1',
'price-tag-1' => 'price-tag-1',
'tag' => 'tag',
'loupe' => 'loupe',
'right-arrow' => 'right-arrow',
'left-arrow-1' => 'left-arrow-1',
'down-arrow' => 'down-arrow',
'price-tag' => 'price-tag',
'stars' => 'stars',
'search' => 'search',
'phone-call-1' => 'phone-call-1',
'award-symbol' => 'award-symbol',
'christmas-stars' => 'christmas-stars',
'minus' => 'minus',
'add' => 'add',
'cancel-1' => 'cancel-1',
'checked' => 'checked',
'cyber-security' => 'cyber-security',
'data-protection' => 'data-protection',
'hosting' => 'hosting',
'brand-awareness' => 'brand-awareness',
'ux-design' => 'ux-design',
'influencer' => 'influencer',
'online-advertising' => 'online-advertising',
'web-management' => 'web-management',
'seo-1' => 'seo-1',
'computer' => 'computer',
'software-development' => 'software-development',
'coding-1' => 'coding-1',
'coding' => 'coding',
'app-development' => 'app-development',
'content-marketing' => 'content-marketing',
'social-media-marketing' => 'social-media-marketing',
'analysis-1' => 'analysis-1',
'twitter' => 'twitter',
'repairing' => 'repairing',
'data-visualization' => 'data-visualization',
'information-technology' => 'information-technology',
'statistics-1' => 'statistics-1',
'exploration' => 'exploration',
'project-1' => 'project-1',
'cross-mark' => 'cross-mark',
'search-analysis' => 'search-analysis',
'system' => 'system',
'hashtag-1' => 'hashtag-1',
'hashtag' => 'hashtag',
'it-department' => 'it-department',
'creative' => 'creative',
'online-analytical' => 'online-analytical',
'secure-data' => 'secure-data',
'slash' => 'slash',
'creative-thinking' => 'creative-thinking',
'right-up' => 'right-up',
'dashboard' => 'dashboard',
'profit' => 'profit',
'project' => 'project',
'phone-call' => 'phone-call',
'seo' => 'seo',
'prototype' => 'prototype',
'creative-process' => 'creative-process',
'growth' => 'growth',
'technical-support' => 'technical-support',
'technology' => 'technology',
'solution-1' => 'solution-1',
'creative-tools' => 'creative-tools',
'data-science' => 'data-science',
'costumer' => 'costumer',
'cooperation' => 'cooperation',
'next' => 'next',
'back' => 'back',
'brand' => 'brand',
'right-arrows' => 'right-arrows',
'idea' => 'idea',
'design-thinking' => 'design-thinking',
'check' => 'check',
'cross' => 'cross',
'right' => 'right',
'link' => 'link',
'server' => 'server',
'analysis' => 'analysis',
'support' => 'support',
'project-management' => 'project-management',
'networking' => 'networking',
'team' => 'team',
'check-mark' => 'check-mark',
'consultation' => 'consultation',
'solution' => 'solution',
'success' => 'success',
'customer-review' => 'customer-review',
'select' => 'select',
'statistics' => 'statistics',
'machine-learning' => 'machine-learning',
'vector' => 'vector',
'trophy' => 'trophy',
'data' => 'data',
'clock' => 'clock',
'cancel' => 'cancel',
'customer-service' => 'customer-service',
'digital-marketing' => 'digital-marketing',
'email' => 'email',
'stats' => 'stats',
'menu' => 'menu',
'location' => 'location',
'tick' => 'tick',
'left-arrow' => 'left-arrow',
'dots-menu' => 'dots-menu',
];
}
public static function getNavigationGroup(): ?string
{
return __('Home');
}
public static function getNavigationLabel(): string
{
return __('Manage Solutions');
}
public function getTitle(): string|Htmlable
{
return 'Solutions';
}
public function getHeading(): string|Htmlable
{
return 'Edit solutions text, icons, and links from here';
}
public function getSubheading(): string|Htmlable|null
{
return 'Manage the solutions section content, including individual solution items.';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,127 @@
<?php
namespace App\Filament\Pages;
use App\Models\UserRole;
use App\Settings\SuccessSettings;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\SettingsPage;
use Illuminate\Contracts\Support\Htmlable;
class ManageSuccess extends SettingsPage
{
protected static ?string $navigationGroup = 'Home';
protected static ?string $navigationIcon = 'heroicon-o-check-circle';
protected static string $settings = SuccessSettings::class;
public function form(Form $form): Form
{
return $form
->schema([
Section::make('Success Section Content')
->description('Manage the main content for the success section.')
->icon('heroicon-o-document-text')
->schema([
TextInput::make('success_subtitle')
->label('Subtitle')
->required()
->maxLength(100),
TextInput::make('success_header')
->label('Header')
->required()
->maxLength(255),
Textarea::make('success_paragraph')
->label('Paragraph')
->required()
->rows(3)
->maxLength(65535),
Grid::make()->schema([
TextInput::make('success_button_text')
->label('Button Text')
->required()
->maxLength(50),
TextInput::make('success_button_url')
->label('Button URL')
->required()
->maxLength(255)
->url(),
])->columns(2),
FileUpload::make('success_image')
->label('Image')
->directory('cms')
->image()
->required(),
]),
Section::make('Skill Items')
->description('Manage the skill items with their names and percentages.')
->icon('heroicon-o-adjustments-vertical')
->schema([
Repeater::make('skill_items')
->label('Skill Items')
->schema([
TextInput::make('name')
->label('Skill Name')
->required()
->maxLength(100),
TextInput::make('percentage')
->label('Percentage')
->numeric()
->required()
->minValue(0)
->maxValue(100),
])
->columns(2)
->minItems(1)
->maxItems(5)
->defaultItems(2)
->reorderable()
->collapsible(),
]),
])
->columns(1)
->statePath('data');
}
public static function getNavigationGroup(): ?string
{
return __('Home');
}
public static function getNavigationLabel(): string
{
return __('Success Section');
}
public function getTitle(): string|Htmlable
{
return 'Success Section';
}
public function getHeading(): string|Htmlable
{
return 'Edit success section content from here';
}
public function getSubheading(): string|Htmlable|null
{
return 'Manage the success section content, including text, button, and skill bars.';
}
public static function canAccess(): bool
{
return auth()->user()->canManageSettings();
}
public static function canView(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ApplicationResource\Pages;
use App\Models\Application;
use App\Models\Career;
use App\Models\UserRole;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class ApplicationResource extends Resource
{
protected static ?string $model = Application::class;
protected static ?string $navigationGroup = 'Careers';
protected static ?string $navigationIcon = 'heroicon-o-document-text';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('career_id')
->label('Career')
->options(Career::all()->pluck('title', 'id'))
->searchable()
->required(),
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\DatePicker::make('birthdate')
->required(),
Forms\Components\TextInput::make('email')
->email()
->required()
->maxLength(255),
Forms\Components\TextInput::make('phone_number')
->maxLength(255),
Forms\Components\FileUpload::make('resume_file')
->required()
->disk('public')
->directory('resumes')
->enableDownload()
->enableOpen(),
Forms\Components\RichEditor::make('cover_letter')
->columnSpan('full'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('career.title')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('name')
->searchable(),
Tables\Columns\TextColumn::make('email')
->searchable(),
Tables\Columns\TextColumn::make('phone_number')
->searchable(),
Tables\Columns\TextColumn::make('birthdate')
->date()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListApplications::route('/'),
'create' => Pages\CreateApplication::route('/create'),
'edit' => Pages\EditApplication::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\ApplicationResource\Pages;
use App\Filament\Resources\ApplicationResource;
use Filament\Resources\Pages\CreateRecord;
class CreateApplication extends CreateRecord
{
protected static string $resource = ApplicationResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ApplicationResource\Pages;
use App\Filament\Resources\ApplicationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditApplication extends EditRecord
{
protected static string $resource = ApplicationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ApplicationResource\Pages;
use App\Filament\Resources\ApplicationResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListApplications extends ListRecords
{
protected static string $resource = ApplicationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\AuthorResource\Pages;
use App\Models\Author;
use Filament\Forms;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
class AuthorResource extends Resource
{
protected static ?string $model = Author::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationGroup = 'News & Stories';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Card::make()
->schema([
TextInput::make('name')
->required()
->maxLength(255),
FileUpload::make('profile_image')
->label('Profile Image 400x400')
->image()
->directory('authors')
->nullable(),
RichEditor::make('description')
->nullable()
->columnSpanFull(),
])->columns(1),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('profile_image')
->square()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListAuthors::route('/'),
'create' => Pages\CreateAuthor::route('/create'),
'edit' => Pages\EditAuthor::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->can('view-authors');
}
public static function canCreate(): bool
{
return auth()->user()->can('view-authors');
}
public static function canEdit(mixed $record): bool
{
return auth()->user()->can('view-authors');
}
public static function canDelete(mixed $record): bool
{
return auth()->user()->can('view-authors');
}
public static function canDeleteAny(): bool
{
return auth()->user()->can('view-authors');
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScopes();
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\AuthorResource\Pages;
use App\Filament\Resources\AuthorResource;
use Filament\Resources\Pages\CreateRecord;
class CreateAuthor extends CreateRecord
{
protected static string $resource = AuthorResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\AuthorResource\Pages;
use App\Filament\Resources\AuthorResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditAuthor extends EditRecord
{
protected static string $resource = AuthorResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\AuthorResource\Pages;
use App\Filament\Resources\AuthorResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListAuthors extends ListRecords
{
protected static string $resource = AuthorResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -3,9 +3,8 @@
namespace App\Filament\Resources;
use App\Filament\Resources\BrandResource\Pages;
use App\Filament\Resources\BrandResource\RelationManagers;
use App\Models\Brand;
use Filament\Forms;
use App\Models\UserRole;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
@@ -16,14 +15,14 @@ use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ToggleColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class BrandResource extends Resource
{
protected static ?string $model = Brand::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationIcon = 'heroicon-o-tag';
protected static ?string $navigationGroup = 'Home';
public static function form(Form $form): Form
{
@@ -36,12 +35,12 @@ class BrandResource extends Resource
FileUpload::make('image')
->image()
->imageEditor()
->rules(['required', 'image',]),
->rules(['required', 'image']),
Toggle::make('active')
->label('Is active')
->onColor('success')
->offColor('danger')
->offColor('danger'),
]);
}
@@ -81,4 +80,9 @@ class BrandResource extends Resource
'index' => Pages\ManageBrands::route('/'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,126 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\CareerResource\Pages;
use App\Filament\Resources\CareerResource\RelationManagers;
use App\Models\Career;
use App\Models\UserRole;
use Filament\Forms;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class CareerResource extends Resource
{
protected static ?string $model = Career::class;
protected static ?string $navigationGroup = 'Careers';
protected static ?string $navigationIcon = 'heroicon-o-briefcase';
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('title')
->required()
->maxLength(255),
TextInput::make('location')
->required()
->maxLength(255),
Textarea::make('title_description')
->label('Description (show on modal)')
->required()
->maxLength(65535)
->columnSpan('full'),
TextInput::make('salary_per_month')
->required()
->numeric()
->label('Salary per month')
->maxLength(255),
Forms\Components\Select::make('salary_currency')
->options(getCurrencies())
->required()
->label('Salary currency'),
Repeater::make('bullets')
->schema([
TextInput::make('bullet')
->required()
->maxLength(255),
])
->minItems(1)
->defaultItems(1)
->columnSpan('full'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->searchable(),
Tables\Columns\TextColumn::make('title_description')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('salary_per_month')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('salary_currency')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('location')
->searchable(),
Tables\Columns\TextColumn::make('salary')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
RelationManagers\ApplicationsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListCareers::route('/'),
'create' => Pages\CreateCareer::route('/create'),
'edit' => Pages\EditCareer::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\CareerResource\Pages;
use App\Filament\Resources\CareerResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCareer extends CreateRecord
{
protected static string $resource = CareerResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CareerResource\Pages;
use App\Filament\Resources\CareerResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditCareer extends EditRecord
{
protected static string $resource = CareerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CareerResource\Pages;
use App\Filament\Resources\CareerResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListCareers extends ListRecords
{
protected static string $resource = CareerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace App\Filament\Resources\CareerResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class ApplicationsRelationManager extends RelationManager
{
protected static string $relationship = 'applications';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\DatePicker::make('birthdate')
->required(),
Forms\Components\FileUpload::make('resume_file')
->required()
->acceptedFileTypes(['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
->disk('public') // or your preferred disk
->directory('resumes'),
Forms\Components\TextInput::make('email')
->email()
->required()
->maxLength(255),
Forms\Components\TextInput::make('phone_number')
->required()
->maxLength(20),
Forms\Components\Textarea::make('cover_letter')
->maxLength(65535)
->nullable()
->columnSpan('full'),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('name')
->columns([
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('email')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('phone_number')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\CommentResource\Pages;
use App\Models\Comment;
use App\Models\UserRole;
use Filament\Forms;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class CommentResource extends Resource
{
protected static ?string $model = Comment::class;
protected static ?string $navigationIcon = 'heroicon-o-chat-bubble-bottom-center-text';
protected static ?string $navigationGroup = 'News & Stories';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Card::make()
->schema([
Select::make('news_id')
->relationship('news', 'title')
->required(),
TextInput::make('title')
->required()
->maxLength(255),
RichEditor::make('message')
->required()
->columnSpanFull(),
TextInput::make('author_name')
->label('Author Name (Optional)')
->maxLength(255),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('news.title')
->label('News Article')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('title')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('author_name')
->label('Author')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListComments::route('/'),
'create' => Pages\CreateComment::route('/create'),
'edit' => Pages\EditComment::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\CommentResource\Pages;
use App\Filament\Resources\CommentResource;
use Filament\Resources\Pages\CreateRecord;
class CreateComment extends CreateRecord
{
protected static string $resource = CommentResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CommentResource\Pages;
use App\Filament\Resources\CommentResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditComment extends EditRecord
{
protected static string $resource = CommentResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CommentResource\Pages;
use App\Filament\Resources\CommentResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListComments extends ListRecords
{
protected static string $resource = CommentResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,129 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\InternshipResource\Pages;
use App\Filament\Resources\InternshipResource\RelationManagers;
use App\Models\Internship;
use App\Models\UserRole;
use Filament\Forms;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class InternshipResource extends Resource
{
protected static ?string $model = Internship::class;
protected static ?string $navigationGroup = 'Careers';
protected static ?string $navigationIcon = 'heroicon-o-academic-cap';
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('title')
->required()
->maxLength(255),
TextInput::make('location')
->required()
->maxLength(255),
Textarea::make('title_description')
->label('Description (show on modal)')
->required()
->maxLength(65535)
->columnSpan('full'),
TextInput::make('salary_per_month')
->required()
->numeric()
->label('Salary per month')
->maxLength(255),
Forms\Components\Select::make('salary_currency')
->options(getCurrencies())
->required()
->label('Salary currency')
->searchable()
->default('USD'),
Repeater::make('bullets')
->schema([
TextInput::make('bullet')
->required()
->maxLength(255),
])
->minItems(1)
->defaultItems(1)
->columnSpan('full'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->searchable(),
Tables\Columns\TextColumn::make('title_description')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('salary_per_month')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('salary_currency')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('location')
->searchable(),
Tables\Columns\TextColumn::make('salary')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
RelationManagers\ApplicationsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListInternships::route('/'),
'create' => Pages\CreateInternship::route('/create'),
'edit' => Pages\EditInternship::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\InternshipResource\Pages;
use App\Filament\Resources\InternshipResource;
use Filament\Resources\Pages\CreateRecord;
class CreateInternship extends CreateRecord
{
protected static string $resource = InternshipResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InternshipResource\Pages;
use App\Filament\Resources\InternshipResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditInternship extends EditRecord
{
protected static string $resource = InternshipResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\InternshipResource\Pages;
use App\Filament\Resources\InternshipResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListInternships extends ListRecords
{
protected static string $resource = InternshipResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace App\Filament\Resources\InternshipResource\RelationManagers;
use App\Models\InternshipApplication;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table; // Added this use statement
class ApplicationsRelationManager extends RelationManager
{
protected static string $relationship = 'applications';
// Add this line to define the inverse relationship
protected static ?string $model = InternshipApplication::class;
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\DatePicker::make('birthdate')
->required(),
Forms\Components\FileUpload::make('resume_file')
->required()
->acceptedFileTypes(['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
->disk('public') // or your preferred disk
->directory('resumes'),
Forms\Components\TextInput::make('email')
->email()
->required()
->maxLength(255),
Forms\Components\TextInput::make('phone_number')
->required()
->maxLength(20),
Forms\Components\Textarea::make('cover_letter')
->maxLength(65535)
->nullable()
->columnSpan('full'),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('name')
->columns([
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('email')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('phone_number')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\NewsResource\Pages;
use App\Filament\Resources\NewsResource\RelationManagers\CommentsRelationManager;
use App\Models\News;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;
class NewsResource extends Resource
{
protected static ?string $model = News::class;
protected static ?string $navigationIcon = 'heroicon-o-newspaper';
protected static ?string $navigationGroup = 'News & Stories';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Card::make()
->schema([
TextInput::make('title')
->required()
->maxLength(255)
->reactive()
->afterStateUpdated(fn (string $operation, $state, Forms\Set $set) => $operation === 'create' ? $set('slug', Str::slug($state)) : null),
TextInput::make('slug')
->required()
->maxLength(255)
->disabled()
->dehydrated()
->unique(News::class, 'slug', ignoreRecord: true),
FileUpload::make('image')
->label('Image 1100x660')
->image()
->directory('news')
->nullable()
->columnSpanFull(),
Select::make('author_id')
->relationship('author', 'name')
->searchable()
->preload()
->required(),
RichEditor::make('content')
->required()
->columnSpanFull(),
DateTimePicker::make('published_at')
->required()
->default(now()),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('image')
->square()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('title')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('slug')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('author.name')
->label('Author Name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('published_at')
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
CommentsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ManageNews::route('/'),
'create' => Pages\CreateNews::route('/create'),
'edit' => Pages\EditNews::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canCreate(): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canEdit(mixed $record): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canDelete(mixed $record): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canDeleteAny(): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScopes();
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\NewsResource\Pages;
use App\Filament\Resources\NewsResource;
use Filament\Resources\Pages\CreateRecord;
class CreateNews extends CreateRecord
{
protected static string $resource = NewsResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\NewsResource\Pages;
use App\Filament\Resources\NewsResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditNews extends EditRecord
{
protected static string $resource = NewsResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\NewsResource\Pages;
use App\Filament\Resources\NewsResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ManageNews extends ListRecords
{
protected static string $resource = NewsResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Filament\Resources\NewsResource\RelationManagers;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class CommentsRelationManager extends RelationManager
{
protected static string $relationship = 'comments';
public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('title')
->required()
->maxLength(255),
RichEditor::make('message')
->required()
->columnSpanFull(),
TextInput::make('author_name')
->label('Author Name (Optional)')
->maxLength(255),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('title')
->columns([
Tables\Columns\TextColumn::make('title')
->searchable(),
Tables\Columns\TextColumn::make('author_name')
->label('Author')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\SolutionResource\Pages;
use App\Models\Solution;
use App\Models\UserRole;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Support\Str;
class SolutionResource extends Resource
{
protected static ?string $model = Solution::class;
protected static ?string $navigationIcon = 'heroicon-o-light-bulb';
protected static ?string $navigationGroup = 'Our Solutions';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('title')
->required()
->maxLength(255)
->reactive()
->afterStateUpdated(fn (string $operation, $state, Forms\Set $set) => $operation === 'create' ? $set('slug', Str::slug($state)) : null)
->debounce('1000ms'),
Forms\Components\TextInput::make('slug')
->required()
->maxLength(255),
Forms\Components\TextInput::make('title_description')
->maxLength(255)
->required()
->columnSpanFull(),
Forms\Components\Repeater::make('bullets')
->schema([
Forms\Components\TextInput::make('bullet')
->label('Bullet Point')
->required(),
])
->columns(1)
->columnSpanFull()
->createItemButtonLabel('Add Bullet Point')
->defaultItems(1),
Forms\Components\Repeater::make('downloads')
->schema([
Forms\Components\TextInput::make('title')
->label('Download Title')
->required(false),
Forms\Components\FileUpload::make('file')
->label('Download File')
->required(false)
->disk('public')
->directory('solution-downloads'),
])
->columns(1)
->columnSpanFull()
->createItemButtonLabel('Add Download Item')
->defaultItems(1),
Forms\Components\Repeater::make('faqs')
->schema([
Forms\Components\TextInput::make('question')
->label('Question')
->required(),
Forms\Components\RichEditor::make('answer')
->label('Answer')
->required(),
])
->columns(1)
->columnSpanFull()
->createItemButtonLabel('Add FAQ')
->defaultItems(1),
Forms\Components\RichEditor::make('description')
->required()
->columnSpanFull(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title')
->searchable(),
Tables\Columns\TextColumn::make('slug')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListSolutions::route('/'),
'create' => Pages\CreateSolution::route('/create'),
'edit' => Pages\EditSolution::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\SolutionResource\Pages;
use App\Filament\Resources\SolutionResource;
use Filament\Resources\Pages\CreateRecord;
class CreateSolution extends CreateRecord
{
protected static string $resource = SolutionResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\SolutionResource\Pages;
use App\Filament\Resources\SolutionResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditSolution extends EditRecord
{
protected static string $resource = SolutionResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\SolutionResource\Pages;
use App\Filament\Resources\SolutionResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListSolutions extends ListRecords
{
protected static string $resource = SolutionResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\SuccessResource\Pages;
use App\Models\Success;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;
class SuccessResource extends Resource
{
protected static ?string $model = Success::class;
protected static ?string $navigationIcon = 'heroicon-o-bookmark-square';
protected static ?string $navigationGroup = 'News & Stories';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Card::make()
->schema([
TextInput::make('title')
->required()
->maxLength(255)
->reactive()
->afterStateUpdated(fn (string $operation, $state, Forms\Set $set) => $operation === 'create' ? $set('slug', Str::slug($state)) : null),
TextInput::make('slug')
->required()
->maxLength(255)
->disabled()
->dehydrated()
->unique(Success::class, 'slug', ignoreRecord: true),
FileUpload::make('image')
->label('Image 1100x660')
->image()
->directory('success')
->nullable()
->columnSpanFull(),
RichEditor::make('content')
->required()
->columnSpanFull(),
DateTimePicker::make('published_at')
->required()
->default(now()),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('image')
->square()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('title')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('slug')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('published_at')
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListSuccesses::route('/'),
'create' => Pages\CreateSuccess::route('/create'),
'edit' => Pages\EditSuccess::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canCreate(): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canEdit(mixed $record): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canDelete(mixed $record): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function canDeleteAny(): bool
{
return auth()->user()->can('manage-news-and-success');
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScopes();
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\SuccessResource\Pages;
use App\Filament\Resources\SuccessResource;
use Filament\Resources\Pages\CreateRecord;
class CreateSuccess extends CreateRecord
{
protected static string $resource = SuccessResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\SuccessResource\Pages;
use App\Filament\Resources\SuccessResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditSuccess extends EditRecord
{
protected static string $resource = SuccessResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\SuccessResource\Pages;
use App\Filament\Resources\SuccessResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListSuccesses extends ListRecords
{
protected static string $resource = SuccessResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\TeamMemberResource\Pages;
use App\Models\TeamMember;
use App\Models\UserRole;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class TeamMemberResource extends Resource
{
protected static ?string $model = TeamMember::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationGroup = 'About US';
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required()
->maxLength(255),
TextInput::make('title')
->required()
->maxLength(255),
Textarea::make('description')
->required()
->rows(5)
->maxLength(65535),
FileUpload::make('image')
->image()
->directory('team-members')
->maxSize(2048) // 2MB
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable()
->sortable(),
TextColumn::make('title')
->searchable()
->sortable(),
ImageColumn::make('image'),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListTeamMembers::route('/'),
'create' => Pages\CreateTeamMember::route('/create'),
'edit' => Pages\EditTeamMember::route('/{record}/edit'),
];
}
public static function canViewAny(): bool
{
return auth()->user()->role === UserRole::ADMIN || auth()->user()->role === UserRole::MANAGER;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\TeamMemberResource\Pages;
use App\Filament\Resources\TeamMemberResource;
use Filament\Resources\Pages\CreateRecord;
class CreateTeamMember extends CreateRecord
{
protected static string $resource = TeamMemberResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\TeamMemberResource\Pages;
use App\Filament\Resources\TeamMemberResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditTeamMember extends EditRecord
{
protected static string $resource = TeamMemberResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\TeamMemberResource\Pages;
use App\Filament\Resources\TeamMemberResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListTeamMembers extends ListRecords
{
protected static string $resource = TeamMemberResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -16,3 +16,165 @@ function logDB(): void
Log::info($query->sql, $query->bindings, $query->time);
});
}
function getCurrencies(): array
{
return [
'AED' => 'UAE dirham',
'AFN' => 'Afghan afghani',
'ALL' => 'Albanian lek',
'AMD' => 'Armenian dram',
'ANG' => 'Netherlands Antillean gulden',
'AOA' => 'Angolan kwanza',
'ARS' => 'Argentine peso',
'AUD' => 'Australian dollar',
'AWG' => 'Aruban florin',
'AZN' => 'Azerbaijani manat',
'BAM' => 'Bosnia and Herzegovina konvertibilna marka',
'BBD' => 'Barbadian dollar',
'BDT' => 'Bangladeshi taka',
'BGN' => 'Bulgarian lev',
'BHD' => 'Bahraini dinar',
'BIF' => 'Burundi franc',
'BMD' => 'Bermudian dollar',
'BND' => 'Brunei dollar',
'BOB' => 'Bolivian boliviano',
'BRL' => 'Brazilian real',
'BSD' => 'Bahamian dollar',
'BTN' => 'Bhutanese ngultrum',
'BWP' => 'Botswana pula',
'BYR' => 'Belarusian ruble',
'BZD' => 'Belize dollar',
'CAD' => 'Canadian dollar',
'CDF' => 'Congolese franc',
'CHF' => 'Swiss franc',
'CLP' => 'Chilean peso',
'CNY' => 'Chinese/Yuan renminbi',
'COP' => 'Colombian peso',
'CRC' => 'Costa Rican colon',
'CUC' => 'Cuban peso',
'CVE' => 'Cape Verdean escudo',
'CZK' => 'Czech koruna',
'DJF' => 'Djiboutian franc',
'DKK' => 'Danish krone',
'DOP' => 'Dominican peso',
'DZD' => 'Algerian dinar',
'EEK' => 'Estonian kroon',
'EGP' => 'Egyptian pound',
'ERN' => 'Eritrean nakfa',
'ETB' => 'Ethiopian birr',
'EUR' => 'European Euro',
'FJD' => 'Fijian dollar',
'FKP' => 'Falkland Islands pound',
'GBP' => 'British pound',
'GEL' => 'Georgian lari',
'GHS' => 'Ghanaian cedi',
'GIP' => 'Gibraltar pound',
'GMD' => 'Gambian dalasi',
'GNF' => 'Guinean franc',
'GQE' => 'Central African CFA franc',
'GTQ' => 'Guatemalan quetzal',
'GYD' => 'Guyanese dollar',
'HKD' => 'Hong Kong dollar',
'HNL' => 'Honduran lempira',
'HRK' => 'Croatian kuna',
'HTG' => 'Haitian gourde',
'HUF' => 'Hungarian forint',
'IDR' => 'Indonesian rupiah',
'ILS' => 'Israeli new sheqel',
'INR' => 'Indian rupee',
'IQD' => 'Iraqi dinar',
'IRR' => 'Iranian rial',
'ISK' => 'Icelandic króna',
'JMD' => 'Jamaican dollar',
'JOD' => 'Jordanian dinar',
'JPY' => 'Japanese yen',
'KES' => 'Kenyan shilling',
'KGS' => 'Kyrgyzstani som',
'KHR' => 'Cambodian riel',
'KMF' => 'Comorian franc',
'KPW' => 'North Korean won',
'KRW' => 'South Korean won',
'KWD' => 'Kuwaiti dinar',
'KYD' => 'Cayman Islands dollar',
'KZT' => 'Kazakhstani tenge',
'LAK' => 'Lao kip',
'LBP' => 'Lebanese lira',
'LKR' => 'Sri Lankan rupee',
'LRD' => 'Liberian dollar',
'LSL' => 'Lesotho loti',
'LTL' => 'Lithuanian litas',
'LVL' => 'Latvian lats',
'LYD' => 'Libyan dinar',
'MAD' => 'Moroccan dirham',
'MDL' => 'Moldovan leu',
'MGA' => 'Malagasy ariary',
'MKD' => 'Macedonian denar',
'MMK' => 'Myanma kyat',
'MNT' => 'Mongolian tugrik',
'MOP' => 'Macanese pataca',
'MRO' => 'Mauritanian ouguiya',
'MUR' => 'Mauritian rupee',
'MVR' => 'Maldivian rufiyaa',
'MWK' => 'Malawian kwacha',
'MXN' => 'Mexican peso',
'MYR' => 'Malaysian ringgit',
'MZM' => 'Mozambican metical',
'NAD' => 'Namibian dollar',
'NGN' => 'Nigerian naira',
'NIO' => 'Nicaraguan córdoba',
'NOK' => 'Norwegian krone',
'NPR' => 'Nepalese rupee',
'NZD' => 'New Zealand dollar',
'OMR' => 'Omani rial',
'PAB' => 'Panamanian balboa',
'PEN' => 'Peruvian nuevo sol',
'PGK' => 'Papua New Guinean kina',
'PHP' => 'Philippine peso',
'PKR' => 'Pakistani rupee',
'PLN' => 'Polish zloty',
'PYG' => 'Paraguayan guarani',
'QAR' => 'Qatari riyal',
'RON' => 'Romanian leu',
'RSD' => 'Serbian dinar',
'RUB' => 'Russian ruble',
'SAR' => 'Saudi riyal',
'SBD' => 'Solomon Islands dollar',
'SCR' => 'Seychellois rupee',
'SDG' => 'Sudanese pound',
'SEK' => 'Swedish krona',
'SGD' => 'Singapore dollar',
'SHP' => 'Saint Helena pound',
'SLL' => 'Sierra Leonean leone',
'SOS' => 'Somali shilling',
'SRD' => 'Surinamese dollar',
'SYP' => 'Syrian pound',
'SZL' => 'Swazi lilangeni',
'THB' => 'Thai baht',
'TJS' => 'Tajikistani somoni',
'TMT' => 'Turkmen manat',
'TND' => 'Tunisian dinar',
'TRY' => 'Turkish new lira',
'TTD' => 'Trinidad and Tobago dollar',
'TWD' => 'New Taiwan dollar',
'TZS' => 'Tanzanian shilling',
'UAH' => 'Ukrainian hryvnia',
'UGX' => 'Ugandan shilling',
'USD' => 'United States dollar',
'UYU' => 'Uruguayan peso',
'UZS' => 'Uzbekistani som',
'VEB' => 'Venezuelan bolivar',
'VND' => 'Vietnamese dong',
'VUV' => 'Vanuatu vatu',
'WST' => 'Samoan tala',
'XAF' => 'Central African CFA franc',
'XCD' => 'East Caribbean dollar',
'XDR' => 'Special Drawing Rights',
'XOF' => 'West African CFA franc',
'XPF' => 'CFP franc',
'YER' => 'Yemeni rial',
'ZAR' => 'South African rand',
'ZMK' => 'Zambian kwacha',
'ZWR' => 'Zimbabwean dollar',
];
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Http\Controllers;
use App\Models\Application;
use Illuminate\Http\Request;
class ApplicationController extends Controller
{
public function store(Request $request)
{
$validatedData = $request->validate([
'career_id' => 'required|exists:careers,id',
'name' => 'required|string|max:255',
'birthdate' => 'required|date',
'resume_file' => 'required|file|mimes:pdf,doc,docx|max:2048',
'email' => 'required|email|max:255',
'phone_number' => 'required|string',
'cover_letter' => 'nullable|string',
]);
$resumePath = $request->file('resume_file')->store('resumes');
Application::create([
'career_id' => $validatedData['career_id'],
'name' => $validatedData['name'],
'birthdate' => $validatedData['birthdate'],
'resume_file' => $resumePath,
'email' => $validatedData['email'],
'phone_number' => $validatedData['phone_number'],
'cover_letter' => $validatedData['cover_letter'] ?? null,
]);
return response()->json([
'message' => 'Your application has been submitted successfully!',
]);
}
}

View File

@@ -2,8 +2,6 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class BrandController extends Controller
{
//

View File

@@ -3,18 +3,14 @@
namespace App\Http\Controllers;
use App\Models\Career;
use Illuminate\Http\Request;
class CareersPageController extends Controller
{
public function index()
{
return view('web.pages.careers.index');
}
$careers = Career::query()->get();
public function store(Request $request)
{
dd($request->all());
return view('web.pages.careers.index', compact('careers'));
}
public function show(Career $career)

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\Brand;
use App\Models\News;
use App\Settings\HomeSettings;
class HomePageController extends Controller
@@ -11,7 +12,8 @@ class HomePageController extends Controller
{
$brands = Brand::query()->get(['id', 'image']);
$homeSettings = app(HomeSettings::class);
$allNews = News::query()->latest()->take(3)->get();
return view('web.pages.home.index', compact('homeSettings', 'brands'));
return view('web.pages.home.index', compact('homeSettings', 'brands', 'allNews'));
}
}

View File

@@ -2,19 +2,46 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Internship;
use App\Models\InternshipApplication;
use Illuminate\Http\Request; // Changed from App\Models\Application
class InternshipsPageController extends Controller
{
public function index()
{
return view('web.pages.internships.index');
$internships = Internship::query()->get();
return view('web.pages.internships.index', compact('internships'));
}
public function store(Request $request)
{
dd($request->all());
$validatedData = $request->validate([
'internship_id' => 'required|exists:internships,id',
'name' => 'required|string|max:255',
'birthdate' => 'required|date',
'resume_file' => 'required|file|mimes:pdf,doc,docx|max:2048',
'email' => 'required|email|max:255',
'phone_number' => 'required|string',
'cover_letter' => 'nullable|string',
]);
$resumePath = $request->file('resume_file')->store('resumes');
InternshipApplication::create([ // Changed to InternshipApplication::create
'internship_id' => $validatedData['internship_id'],
'name' => $validatedData['name'],
'birthdate' => $validatedData['birthdate'],
'resume_file' => $resumePath,
'email' => $validatedData['email'],
'phone_number' => $validatedData['phone_number'],
'cover_letter' => $validatedData['cover_letter'] ?? null,
]);
return response()->json([
'message' => 'Your application has been submitted successfully!',
]);
}
public function show(Internship $internship)

View File

@@ -3,16 +3,35 @@
namespace App\Http\Controllers;
use App\Models\News;
use Illuminate\Http\Request;
class NewsPageController extends Controller
{
public function index()
{
return view('web.pages.news.index');
$allNews = News::query()->with('author')->latest()->get();
return view('web.pages.news.index', compact('allNews'));
}
public function show(News $news)
public function show($news)
{
return view('web.pages.news.show', compact('news'));
$news = News::where('slug', $news)->with('author', 'comments')->first();
$recentNews = News::query()->with('author')->latest()->limit(3)->get();
return view('web.pages.news.show', compact('news', 'recentNews'));
}
public function storeComment(Request $request, News $news)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'message' => 'required|string',
'author_name' => 'nullable|string|max:255',
]);
$news->comments()->create($validated);
return back()->with('success', 'Comment added successfully!');
}
}

View File

@@ -8,10 +8,12 @@ class OurSolutionPageController extends Controller
{
public function index()
{
return view('web.pages.our-solutions.index');
}
public function show(Solution $solution)
$solutions = Solution::query()->latest()->get();
return view('web.pages.our-solutions.index', compact('solutions'));
}
public function show(Solution $solution)
{
return view('web.pages.our-solutions.show', compact('solution'));
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\Success;
class SuccessPageController extends Controller
{
public function index()
{
$allSuccesses = Success::query()->latest()->get();
return view('web.pages.success.index', compact('allSuccesses'));
}
public function show($success)
{
$success = Success::where('slug', $success)->firstOrFail();
$recentSuccesses = Success::query()->latest()->limit(3)->get();
return view('web.pages.success.show', compact('success', 'recentSuccesses'));
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Session;
use Symfony\Component\HttpFoundation\Response;
class SetLocale
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$locale = $request->query('lang');
if ($locale && in_array($locale, config('app.available_locales'))) {
App::setLocale($locale);
Session::put('locale', $locale);
} elseif (Session::has('locale')) {
App::setLocale(Session::get('locale'));
} else {
App::setLocale(config('app.fallback_locale', 'en'));
}
return $next($request);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Application extends Model
{
protected $fillable = [
'career_id',
'name',
'birthdate',
'resume_file',
'email',
'phone_number',
'cover_letter',
];
public function career(): BelongsTo
{
return $this->belongsTo(Career::class);
}
}

23
app/Models/Author.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Author extends Model
{
use HasFactory;
protected $fillable = [
'name',
'description',
'profile_image',
];
public function news(): HasMany
{
return $this->hasMany(News::class);
}
}

View File

@@ -9,7 +9,7 @@ use Illuminate\Support\Facades\Storage;
* @property int $id
* @property string $name
* @property string $image
* @property boolean $active
* @property bool $active
* @property \Illuminate\Support\Facades\Date $created_at
* @property \Illuminate\Support\Facades\Date $updated_at
*/
@@ -17,6 +17,7 @@ class Brand extends Model
{
/**
* Casts
*
* @var array<string, string>
*/
protected $casts = [
@@ -40,6 +41,6 @@ class Brand extends Model
*/
public function imageUrl(): string
{
return url('/storage/' . $this->image);
return url('/storage/'.$this->image);
}
}

View File

@@ -3,13 +3,25 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Career extends Model
{
protected $fillable = [
'title',
'description',
'title_description',
'salary_per_month',
'bullets',
'location',
'salary',
'salary_currency',
];
protected $casts = [
'bullets' => 'array',
];
public function applications(): HasMany
{
return $this->hasMany(Application::class);
}
}

24
app/Models/Comment.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Comment extends Model
{
use HasFactory;
protected $fillable = [
'title',
'message',
'author_name',
'news_id',
];
public function news(): BelongsTo
{
return $this->belongsTo(News::class);
}
}

View File

@@ -3,8 +3,25 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Internship extends Model
{
//
protected $fillable = [
'title',
'title_description',
'salary_per_month',
'bullets',
'location',
'salary_currency',
];
protected $casts = [
'bullets' => 'array',
];
public function applications(): HasMany
{
return $this->hasMany(InternshipApplication::class);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class InternshipApplication extends Model
{
protected $fillable = [
'internship_id',
'name',
'birthdate',
'resume_file',
'email',
'phone_number',
'cover_letter',
];
public function internship(): BelongsTo
{
return $this->belongsTo(Internship::class);
}
}

View File

@@ -4,6 +4,8 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class News extends Model
{
@@ -13,6 +15,18 @@ class News extends Model
'title',
'slug',
'content',
'image',
'published_at',
'author_id',
];
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
public function author(): BelongsTo
{
return $this->belongsTo(Author::class);
}
}

View File

@@ -13,5 +13,15 @@ class Solution extends Model
'title',
'description',
'slug',
'title_description',
'bullets',
'downloads',
'faqs',
];
}
protected $casts = [
'bullets' => 'array',
'downloads' => 'array',
'faqs' => 'array',
];
}

View File

@@ -15,4 +15,4 @@ class Story extends Model
'content',
'published_at',
];
}
}

19
app/Models/Success.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Success extends Model
{
use HasFactory;
protected $fillable = [
'title',
'slug',
'content',
'image',
'published_at',
];
}

10
app/Models/TeamMember.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TeamMember extends Model
{
//
}

View File

@@ -2,6 +2,13 @@
namespace App\Models;
enum UserRole: string
{
case ADMIN = 'admin';
case MANAGER = 'manager';
case NEWS_WRITER = 'news_writer';
}
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
@@ -21,6 +28,7 @@ class User extends Authenticatable
'name',
'email',
'password',
'role',
];
/**
@@ -43,6 +51,12 @@ class User extends Authenticatable
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
'role' => UserRole::class,
];
}
public function canManageSettings(): bool
{
return $this->role === UserRole::ADMIN || $this->role === UserRole::MANAGER;
}
}

View File

@@ -2,11 +2,10 @@
namespace App\Providers;
use App\Models\Brand;
use App\Models\Solution;
use App\Settings\SiteSettings;
use App\Settings\SiteSocialSettings;
use Illuminate\Database\Eloquent\Model;
use App\Settings\HomeSettings;
use Illuminate\Support\Facades\View as ViewFacade;
use Illuminate\Support\ServiceProvider;
use Illuminate\View\View;
@@ -29,6 +28,7 @@ class AppServiceProvider extends ServiceProvider
Model::unguard();
$this->addSettingsToViews();
$this->addSolutionsToViews();
// logDB();
}
@@ -43,4 +43,14 @@ class AppServiceProvider extends ServiceProvider
$view->with('socialMedia', app(SiteSocialSettings::class));
});
}
/**
* Add solutions to views
*/
public function addSolutionsToViews(): void
{
ViewFacade::composer(['web.layouts.navigation.header'], function (View $view) {
$view->with('solutions', Solution::query()->latest()->get());
});
}
}

View File

@@ -2,8 +2,12 @@
namespace App\Providers\Filament;
use App\Filament\Pages\HomePageSettings;
use App\Filament\Pages\ManageCtaSettings;
use App\Filament\Resources\ApplicationResource;
use App\Models\User;
use App\Models\UserRole;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
@@ -15,8 +19,11 @@ use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Support\Facades\Gate;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Filament\SpatieLaravelTranslatablePlugin;
class PanelPanelProvider extends PanelProvider
{
@@ -27,18 +34,30 @@ class PanelPanelProvider extends PanelProvider
->id('panel')
->path('panel')
->login()
->profile()
->colors([
'primary' => Color::Amber,
])
->navigationGroups([
'Home',
'About US',
'Our Solutions',
'News & Stories',
'Careers',
'Contact',
'Settings',
'Activities',
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
Pages\Dashboard::class,
HomePageSettings::class,
ManageCtaSettings::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
@@ -56,6 +75,34 @@ class PanelPanelProvider extends PanelProvider
])
->resources([
config('filament-logger.activity_resource'),
]);
ApplicationResource::class,
])
->plugin(
SpatieLaravelTranslatablePlugin::make()
->defaultLocales(['en', 'ru', 'tk'])
);
}
public function boot(): void
{
Gate::before(function (User $user, string $ability) {
if ($user->role === UserRole::ADMIN) {
return true;
}
return null;
});
Gate::define('view-activity-logs', function (User $user) {
return $user->role === UserRole::ADMIN;
});
Gate::define('manage-news-and-success', function (User $user) {
return $user->role === UserRole::NEWS_WRITER || $user->role === UserRole::ADMIN || $user->role === UserRole::MANAGER;
});
Gate::define('view-authors', function (User $user) {
return $user->role === UserRole::NEWS_WRITER || $user->role === UserRole::ADMIN || $user->role === UserRole::MANAGER;
});
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class AboutSettings extends Settings
{
// Our Story Section
public string $our_story_title;
public string $our_story_subtitle;
public string $our_story_paragraph_one;
public string $our_story_paragraph_two;
public string $our_story_paragraph_three;
public string $our_story_button_text;
public string $our_story_button_url;
public string $our_story_video_poster;
public string $our_story_video_source;
// Our Journey Section
public string $our_journey_title;
public string $our_journey_subtitle;
public array $our_journey_milestones; // [{year: 2010, title: "Start Company", description: "...", image: "..."}]
// Company Structure Section
public string $company_structure_title;
public string $company_structure_subtitle;
public string $company_structure_director_name;
public string $company_structure_advisor_name;
public array $company_structure_departments; // [{name: "HSE", person: "Michael Brown"}]
// Our Facilities Section
public string $our_facilities_title;
public string $our_facilities_subtitle;
public array $our_facilities_locations; // [{name: "Headquarters", location: "...", description: "...", image: "...", tags: ["R&D Labs"]}]
public static function group(): string
{
return 'cms_aboutpage';
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class ContactSettings extends Settings
{
public string $contact_subtitle = 'Default Contact Subtitle';
public string $contact_header = 'Default Contact Header';
public string $contact_paragraph = 'This is a default paragraph for the contact page. Please update it from the Filament panel.';
public string $phone_number = '+1234567890';
public string $email_address = 'info@example.com';
public string $location_address = '123 Main St, Anytown, USA';
public string $map_embed_url = '';
public static function group(): string
{
return 'contact';
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class CtaSettings extends Settings
{
public string $title;
public string $button_text;
public string $button_url;
public string $background_image;
public static function group(): string
{
return 'cta';
}
}

View File

@@ -44,6 +44,30 @@ class HomeSettings extends Settings
public string $about_image_two;
public string $industry_subtitle;
public string $industry_header;
public string $industry_paragraph;
public string $industry_button_text;
public string $industry_button_url;
public string $industry_image_one;
public array $industry_items;
public string $text_slide_subtitle;
public string $text_slide_header;
public string $text_slide_image;
public int $text_slide_counter_number;
public array $text_slide_items;
public static function group(): string
{
return 'cms_homepage';

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class PortfolioSettings extends Settings
{
public string $portfolio_header;
public string $portfolio_button_text;
public string $portfolio_button_url;
public array $portfolio_items;
public static function group(): string
{
return 'cms_portfolio';
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class SolutionSettings extends Settings
{
public string $solutions_subtitle;
public string $solutions_header;
public string $solutions_button_text;
public string $solutions_button_url;
public ?string $solutions_image;
public array $solution_items;
public static function group(): string
{
return 'cms_solutions';
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class SuccessSettings extends Settings
{
public string $success_subtitle;
public string $success_header;
public string $success_paragraph;
public string $success_button_text;
public string $success_button_url;
public array $skill_items;
public string $success_image;
public static function group(): string
{
return 'cms_success';
}
}

View File

@@ -12,6 +12,9 @@ return Application::configure(basePath: dirname(__DIR__))
)
->withMiddleware(function (Middleware $middleware) {
//
$middleware->web(append: [
\App\Http\Middleware\SetLocale::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//

View File

@@ -9,8 +9,10 @@
"php": "^8.2",
"filament/filament": "^3.3",
"filament/spatie-laravel-settings-plugin": "^3.2",
"filament/spatie-laravel-translatable-plugin": "^3.2",
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1",
"spatie/laravel-translatable": "^6.11",
"z3d0x/filament-logger": "^0.8.0"
},
"require-dev": {
@@ -58,6 +60,10 @@
"Composer\\Config::disableProcessTimeout",
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
],
"network": [
"Composer\\Config::disableProcessTimeout",
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve --host=0.0.0.0\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
],
"test": [
"@php artisan config:clear --ansi",
"@php artisan test"

661
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -84,6 +84,19 @@ return [
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
/*
|--------------------------------------------------------------------------
| Application Available Locales
|--------------------------------------------------------------------------
|
| The application locales that are available for your application.
|
*/
'available_locales' => [
'en', 'ru', 'tk'
],
/*
|--------------------------------------------------------------------------
| Encryption Key

101
config/filament.php Normal file
View File

@@ -0,0 +1,101 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Broadcasting
|--------------------------------------------------------------------------
|
| By uncommenting the Laravel Echo configuration, you may connect Filament
| to any Pusher-compatible websockets server.
|
| This will allow your users to receive real-time notifications.
|
*/
'broadcasting' => [
// 'echo' => [
// 'broadcaster' => 'pusher',
// 'key' => env('VITE_PUSHER_APP_KEY'),
// 'cluster' => env('VITE_PUSHER_APP_CLUSTER'),
// 'wsHost' => env('VITE_PUSHER_HOST'),
// 'wsPort' => env('VITE_PUSHER_PORT'),
// 'wssPort' => env('VITE_PUSHER_PORT'),
// 'authEndpoint' => '/broadcasting/auth',
// 'disableStats' => true,
// 'encrypted' => true,
// 'forceTLS' => true,
// ],
],
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| This is the storage disk Filament will use to store files. You may use
| any of the disks defined in the `config/filesystems.php`.
|
*/
'default_filesystem_disk' => env('FILAMENT_FILESYSTEM_DISK', 'public'),
/*
|--------------------------------------------------------------------------
| Assets Path
|--------------------------------------------------------------------------
|
| This is the directory where Filament's assets will be published to. It
| is relative to the `public` directory of your Laravel application.
|
| After changing the path, you should run `php artisan filament:assets`.
|
*/
'assets_path' => null,
/*
|--------------------------------------------------------------------------
| Cache Path
|--------------------------------------------------------------------------
|
| This is the directory that Filament will use to store cache files that
| are used to optimize the registration of components.
|
| After changing the path, you should run `php artisan filament:cache-components`.
|
*/
'cache_path' => base_path('bootstrap/cache/filament'),
/*
|--------------------------------------------------------------------------
| Livewire Loading Delay
|--------------------------------------------------------------------------
|
| This sets the delay before loading indicators appear.
|
| Setting this to 'none' makes indicators appear immediately, which can be
| desirable for high-latency connections. Setting it to 'default' applies
| Livewire's standard 200ms delay.
|
*/
'livewire_loading_delay' => 'default',
/*
|--------------------------------------------------------------------------
| System Route Prefix
|--------------------------------------------------------------------------
|
| This is the prefix used for the system routes that Filament registers,
| such as the routes for downloading exports and failed import rows.
|
*/
'system_route_prefix' => 'filament',
];

160
config/livewire.php Normal file
View File

@@ -0,0 +1,160 @@
<?php
return [
/*
|---------------------------------------------------------------------------
| Class Namespace
|---------------------------------------------------------------------------
|
| This value sets the root class namespace for Livewire component classes in
| your application. This value will change where component auto-discovery
| finds components. It's also referenced by the file creation commands.
|
*/
'class_namespace' => 'App\\Livewire',
/*
|---------------------------------------------------------------------------
| View Path
|---------------------------------------------------------------------------
|
| This value is used to specify where Livewire component Blade templates are
| stored when running file creation commands like `artisan make:livewire`.
| It is also used if you choose to omit a component's render() method.
|
*/
'view_path' => resource_path('views/livewire'),
/*
|---------------------------------------------------------------------------
| Layout
|---------------------------------------------------------------------------
| The view that will be used as the layout when rendering a single component
| as an entire page via `Route::get('/post/create', CreatePost::class);`.
| In this case, the view returned by CreatePost will render into $slot.
|
*/
'layout' => 'components.layouts.app',
/*
|---------------------------------------------------------------------------
| Lazy Loading Placeholder
|---------------------------------------------------------------------------
| Livewire allows you to lazy load components that would otherwise slow down
| the initial page load. Every component can have a custom placeholder or
| you can define the default placeholder view for all components below.
|
*/
'lazy_placeholder' => null,
/*
|---------------------------------------------------------------------------
| Temporary File Uploads
|---------------------------------------------------------------------------
|
| Livewire handles file uploads by storing uploads in a temporary directory
| before the file is stored permanently. All file uploads are directed to
| a global endpoint for temporary storage. You may configure this below:
|
*/
'temporary_file_upload' => [
'disk' => null, // Example: 'local', 's3' | Default: 'default'
'rules' => ['required', 'file', 'max:100000'], // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB)
'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
'mov', 'avi', 'wmv', 'mp3', 'm4a',
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
],
'max_upload_time' => 20, // Max duration (in minutes) before an upload is invalidated...
'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
],
/*
|---------------------------------------------------------------------------
| Render On Redirect
|---------------------------------------------------------------------------
|
| This value determines if Livewire will run a component's `render()` method
| after a redirect has been triggered using something like `redirect(...)`
| Setting this to true will render the view once more before redirecting
|
*/
'render_on_redirect' => false,
/*
|---------------------------------------------------------------------------
| Eloquent Model Binding
|---------------------------------------------------------------------------
|
| Previous versions of Livewire supported binding directly to eloquent model
| properties using wire:model by default. However, this behavior has been
| deemed too "magical" and has therefore been put under a feature flag.
|
*/
'legacy_model_binding' => false,
/*
|---------------------------------------------------------------------------
| Auto-inject Frontend Assets
|---------------------------------------------------------------------------
|
| By default, Livewire automatically injects its JavaScript and CSS into the
| <head> and <body> of pages containing Livewire components. By disabling
| this behavior, you need to use @livewireStyles and @livewireScripts.
|
*/
'inject_assets' => true,
/*
|---------------------------------------------------------------------------
| Navigate (SPA mode)
|---------------------------------------------------------------------------
|
| By adding `wire:navigate` to links in your Livewire application, Livewire
| will prevent the default link handling and instead request those pages
| via AJAX, creating an SPA-like effect. Configure this behavior here.
|
*/
'navigate' => [
'show_progress_bar' => true,
'progress_bar_color' => '#2299dd',
],
/*
|---------------------------------------------------------------------------
| HTML Morph Markers
|---------------------------------------------------------------------------
|
| Livewire intelligently "morphs" existing HTML into the newly rendered HTML
| after each update. To make this process more reliable, Livewire injects
| "markers" into the rendered Blade surrounding @if, @class & @foreach.
|
*/
'inject_morph_markers' => true,
/*
|---------------------------------------------------------------------------
| Pagination Theme
|---------------------------------------------------------------------------
|
| When enabling Livewire's pagination feature by using the `WithPagination`
| trait, Livewire will use Tailwind templates to render pagination views
| on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
|
*/
'pagination_theme' => 'tailwind',
];

View File

@@ -14,6 +14,7 @@ return [
GeneralSettings::class,
SiteSettings::class,
HomeSettings::class,
\App\Settings\ContactSettings::class,
],
/*

View File

@@ -0,0 +1,25 @@
<?php
namespace Database\Factories;
use App\Models\News;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class NewsFactory extends Factory
{
protected $model = News::class;
public function definition()
{
$title = $this->faker->sentence(6);
return [
'title' => $title,
'slug' => Str::slug($title),
'content' => $this->faker->paragraphs(3, true),
'image' => 'news/'.$this->faker->image('public/storage/news', 640, 480, null, false),
'published_at' => $this->faker->dateTimeBetween('-1 year', 'now'),
];
}
}

View File

@@ -13,6 +13,9 @@ return new class extends Migration
{
Schema::create('solutions', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description');
$table->string('slug')->unique();
$table->timestamps();
});
}

View File

@@ -13,6 +13,11 @@ return new class extends Migration
{
Schema::create('news', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->longText('content');
$table->string('image')->nullable();
$table->timestamp('published_at');
$table->timestamps();
});
}

View File

@@ -14,9 +14,10 @@ return new class extends Migration
Schema::create('careers', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description');
$table->text('title_description')->nullable();
$table->string('salary_per_month')->nullable();
$table->json('bullets')->nullable();
$table->string('location');
$table->string('salary')->nullable();
$table->timestamps();
});
}

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('news', function (Blueprint $table) {
$table->string('author')->after('image')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('news', function (Blueprint $table) {
$table->dropColumn('author');
});
}
};

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('message');
$table->string('author_name')->nullable();
$table->foreignId('news_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('comments');
}
};

View File

@@ -0,0 +1,14 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('cta.title', 'Join Our Community and Access Exclusive Insights Today');
$this->migrator->add('cta.button_text', 'Free Consultation');
$this->migrator->add('cta.button_url', 'request-quote.html');
$this->migrator->add('cta.background_image', '');
}
};

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('solutions', function (Blueprint $table) {
$table->string('title_description')->nullable()->after('description');
$table->json('bullets')->nullable()->after('title_description');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('solutions', function (Blueprint $table) {
$table->dropColumn(['title_description', 'bullets']);
});
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('news', function (Blueprint $table) {
$table->longText('author_description')->nullable()->after('author');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('news', function (Blueprint $table) {
$table->dropColumn('author_description');
});
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->longText('description')->nullable();
$table->string('profile_image')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('authors');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('news', function (Blueprint $table) {
$table->foreignId('author_id')->nullable()->constrained()->onDelete('set null');
$table->dropColumn('author');
$table->dropColumn('author_description');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('news', function (Blueprint $table) {
$table->dropForeign(['author_id']);
$table->dropColumn('author_id');
$table->string('author')->nullable();
$table->string('author_description')->nullable();
});
}
};

Some files were not shown because too many files have changed in this diff Show More