From d29b3ba48949cbb744135f08ca2eaaee1b1e6cae Mon Sep 17 00:00:00 2001 From: Subash Date: Thu, 21 Aug 2025 23:23:38 +0545 Subject: [PATCH] Add Franchise and Newsletter management features - Implemented FranchiseController with CRUD operations and data handling. - Created NewsletterController for managing newsletter subscriptions. - Added routes for Franchise and Newsletter resources in web.php. - Developed views for Franchise and Newsletter management including index, create, edit, and datatable actions. - Introduced form handling and validation for Franchise and Newsletter submissions. - Created database migrations for franchises and newsletters tables. - Updated sidebar configuration to include Franchise and Newsletter sections. - Enhanced client-side forms with AJAX submission for Franchise and Newsletter. --- .../Http/Controllers/FranchiseController.php | 116 ++++++++++++++++++ .../Http/Controllers/NewsletterController.php | 115 +++++++++++++++++ Modules/CCMS/app/Models/Franchise.php | 37 ++++++ Modules/CCMS/app/Models/Newsletter.php | 19 +++ ..._08_21_165811_create_newsletters_table.php | 28 +++++ ...5_08_21_165829_create_franchises_table.php | 40 ++++++ .../views/franchise/create.blade.php | 14 +++ .../franchise/datatable/action.blade.php | 10 ++ .../resources/views/franchise/edit.blade.php | 14 +++ .../resources/views/franchise/index.blade.php | 41 +++++++ .../views/franchise/partials/_form.blade.php | 71 +++++++++++ .../views/newsletter/create.blade.php | 14 +++ .../newsletter/datatable/action.blade.php | 8 ++ .../resources/views/newsletter/edit.blade.php | 14 +++ .../views/newsletter/index.blade.php | 33 +++++ .../views/newsletter/partials/_form.blade.php | 71 +++++++++++ Modules/CCMS/routes/web.php | 5 + config/sidebar.php | 46 ++++--- .../client/raffles/layouts/app.blade.php | 80 ++++++++++++ .../raffles/layouts/partials/footer.blade.php | 6 +- .../raffles/pages/csr-template.blade.php | 6 +- .../pages/franchise-template.blade.php | 52 ++++---- .../pages/test-single-template.blade.php | 82 ++++++++----- 23 files changed, 843 insertions(+), 79 deletions(-) create mode 100644 Modules/CCMS/app/Http/Controllers/FranchiseController.php create mode 100644 Modules/CCMS/app/Http/Controllers/NewsletterController.php create mode 100644 Modules/CCMS/app/Models/Franchise.php create mode 100644 Modules/CCMS/app/Models/Newsletter.php create mode 100644 Modules/CCMS/database/migrations/2025_08_21_165811_create_newsletters_table.php create mode 100644 Modules/CCMS/database/migrations/2025_08_21_165829_create_franchises_table.php create mode 100644 Modules/CCMS/resources/views/franchise/create.blade.php create mode 100644 Modules/CCMS/resources/views/franchise/datatable/action.blade.php create mode 100644 Modules/CCMS/resources/views/franchise/edit.blade.php create mode 100644 Modules/CCMS/resources/views/franchise/index.blade.php create mode 100644 Modules/CCMS/resources/views/franchise/partials/_form.blade.php create mode 100644 Modules/CCMS/resources/views/newsletter/create.blade.php create mode 100644 Modules/CCMS/resources/views/newsletter/datatable/action.blade.php create mode 100644 Modules/CCMS/resources/views/newsletter/edit.blade.php create mode 100644 Modules/CCMS/resources/views/newsletter/index.blade.php create mode 100644 Modules/CCMS/resources/views/newsletter/partials/_form.blade.php diff --git a/Modules/CCMS/app/Http/Controllers/FranchiseController.php b/Modules/CCMS/app/Http/Controllers/FranchiseController.php new file mode 100644 index 0000000..a6c5191 --- /dev/null +++ b/Modules/CCMS/app/Http/Controllers/FranchiseController.php @@ -0,0 +1,116 @@ +ajax()) { + $model = Franchise::query()->latest(); + return DataTables::eloquent($model) + ->addIndexColumn() + ->addColumn('action', 'ccms::franchise.datatable.action') + ->rawColumns(['action']) + ->toJson(); + } + return view('ccms::franchise.index', [ + 'title' => 'Franchise List', + ]); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + // + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + try { + $rules = [ + 'first_name' => 'required|string', + 'email' => 'required|email', + ]; + + if (setting('enable_reCaptcha') == 1) { + $rules['g-recaptcha-response'] = ['required', new Recaptcha]; + } + + $messages = [ + 'email.email' => 'Must be a valid email address.', + 'g-recaptcha-response.required' => 'Please complete reCAPTCHA validation.', + 'g-recaptcha-response' => 'Invalid reCAPTCHA.', + ]; + + $validator = Validator::make($request->all(), $rules, $messages); + if ($validator->fails()) { + return response()->json(['errors' => $validator->errors()], 422); + } + + Franchise::create($validator->validated()); + + return response()->json(['status' => 200, 'message' => "Thank you for reaching out! Your message has been received and we'll get back to you shortly."], 200); + } catch (\Exception $e) { + return response()->json(['status' => 500, 'message' => 'Internal server error', 'error' => $e->getMessage()], 500); + } + } + + /** + * Show the specified resource. + */ + public function show($id) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit($id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, $id) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy($id) + { + try { + $franchise = Franchise::whereId($id)->first(); + if ($franchise) { + $franchise->delete(); + } + return response()->json(['status' => 200, 'message' => 'Franchise has been deleted!'], 200); + } catch (\Throwable $th) { + return redirect()->back()->with('error', $th->getMessage()); + } + } + +} diff --git a/Modules/CCMS/app/Http/Controllers/NewsletterController.php b/Modules/CCMS/app/Http/Controllers/NewsletterController.php new file mode 100644 index 0000000..db7f764 --- /dev/null +++ b/Modules/CCMS/app/Http/Controllers/NewsletterController.php @@ -0,0 +1,115 @@ +ajax()) { + $model = Newsletter::query()->latest(); + return DataTables::eloquent($model) + ->addIndexColumn() + ->addColumn('action', 'ccms::newsletter.datatable.action') + ->rawColumns(['action']) + ->toJson(); + } + return view('ccms::newsletter.index', [ + 'title' => 'Newsletter List', + ]); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + // + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + try { + $rules = [ + 'email' => 'required|email', + ]; + + if (setting('enable_reCaptcha') == 1) { + $rules['g-recaptcha-response'] = ['required', new Recaptcha]; + } + + $messages = [ + 'email.email' => 'Must be a valid email address.', + 'g-recaptcha-response.required' => 'Please complete reCAPTCHA validation.', + 'g-recaptcha-response' => 'Invalid reCAPTCHA.', + ]; + + $validator = Validator::make($request->all(), $rules, $messages); + if ($validator->fails()) { + return response()->json(['errors' => $validator->errors()], 422); + } + + Newsletter::create($validator->validated()); + + return response()->json(['status' => 200, 'message' => "Thank you for reaching out! Your message has been received and we'll get back to you shortly."], 200); + } catch (\Exception $e) { + return response()->json(['status' => 500, 'message' => 'Internal server error', 'error' => $e->getMessage()], 500); + } + } + + /** + * Show the specified resource. + */ + public function show($id) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit($id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, $id) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy($id) + { + try { + $newsletter = Newsletter::whereId($id)->first(); + if ($newsletter) { + $newsletter->delete(); + } + return response()->json(['status' => 200, 'message' => 'Newsletter has been deleted!'], 200); + } catch (\Throwable $th) { + return redirect()->back()->with('error', $th->getMessage()); + } + } + +} diff --git a/Modules/CCMS/app/Models/Franchise.php b/Modules/CCMS/app/Models/Franchise.php new file mode 100644 index 0000000..f7d7d3c --- /dev/null +++ b/Modules/CCMS/app/Models/Franchise.php @@ -0,0 +1,37 @@ +id(); + $table->string('email')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('newsletters'); + } +}; diff --git a/Modules/CCMS/database/migrations/2025_08_21_165829_create_franchises_table.php b/Modules/CCMS/database/migrations/2025_08_21_165829_create_franchises_table.php new file mode 100644 index 0000000..757e355 --- /dev/null +++ b/Modules/CCMS/database/migrations/2025_08_21_165829_create_franchises_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('first_name')->nullable(); + $table->string('last_name')->nullable(); + $table->string('email')->nullable(); + $table->string('phone')->nullable(); + $table->string('address')->nullable(); + $table->string('city')->nullable(); + $table->string('state')->nullable(); + $table->string('invest_level')->nullable(); + $table->string('own_business')->nullable(); + $table->text('yes_own_des')->nullable(); + $table->string('franchise_location')->nullable(); + $table->string('start_time_frame')->nullable(); + $table->string('office_setup')->nullable(); + $table->string('website')->nullable(); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('franchises'); + } +}; diff --git a/Modules/CCMS/resources/views/franchise/create.blade.php b/Modules/CCMS/resources/views/franchise/create.blade.php new file mode 100644 index 0000000..b386130 --- /dev/null +++ b/Modules/CCMS/resources/views/franchise/create.blade.php @@ -0,0 +1,14 @@ +@extends('layouts.app') +@section('content') +
+ + + + {{ html()->form('POST')->route('testimonial.store')->class(['needs-validation'])->attributes(['enctype' => 'multipart/form-data', 'novalidate'])->open() }} + + @include('ccms::testimonial.partials._form') + + {{ html()->form()->close() }} + +
+@endsection diff --git a/Modules/CCMS/resources/views/franchise/datatable/action.blade.php b/Modules/CCMS/resources/views/franchise/datatable/action.blade.php new file mode 100644 index 0000000..e220d39 --- /dev/null +++ b/Modules/CCMS/resources/views/franchise/datatable/action.blade.php @@ -0,0 +1,10 @@ +
+ + {{-- --}} + + + + + +
diff --git a/Modules/CCMS/resources/views/franchise/edit.blade.php b/Modules/CCMS/resources/views/franchise/edit.blade.php new file mode 100644 index 0000000..5d96439 --- /dev/null +++ b/Modules/CCMS/resources/views/franchise/edit.blade.php @@ -0,0 +1,14 @@ +@extends('layouts.app') +@section('content') +
+ + + + {{ html()->modelForm($testimonial, 'PUT')->route('testimonial.update', $testimonial->id)->class(['needs-validation'])->attributes(['novalidate'])->open() }} + + @include('ccms::testimonial.partials._form') + + {{ html()->form()->close() }} + +
+@endsection diff --git a/Modules/CCMS/resources/views/franchise/index.blade.php b/Modules/CCMS/resources/views/franchise/index.blade.php new file mode 100644 index 0000000..18a4159 --- /dev/null +++ b/Modules/CCMS/resources/views/franchise/index.blade.php @@ -0,0 +1,41 @@ +@extends('layouts.app') +@section('content') +
+ +
+
+
{{ $title }}
+
+
+ @php + $columns = [ + [ + 'title' => 'S.N', + 'data' => 'DT_RowIndex', + 'name' => 'DT_RowIndex', + 'orderable' => false, + 'searchable' => false, + 'sortable' => false, + ], + ['title' => 'First Name', 'data' => 'name', 'first_name' => 'first_name'], + ['title' => 'Last Name', 'data' => 'name', 'first_name' => 'first_name'], + ['title' => 'Email', 'data' => 'email', 'name' => 'email'], + ['title' => 'Phone', 'data' => 'phone', 'name' => 'phone'], + ['title' => 'Address', 'data' => 'address', 'name' => 'address'], + ['title' => 'City', 'data' => 'city', 'name' => 'city'], + ['title' => 'State', 'data' => 'state', 'name' => 'state'], + ['title' => 'Invest Level', 'data' => 'invest_level', 'name' => 'invest_level'], + ['title' => 'Franchise Location', 'data' => 'franchise_location', 'name' => 'franchise_location'], + [ + 'title' => 'Action', + 'data' => 'action', + 'orderable' => false, + 'searchable' => false, + ], + ]; + @endphp + +
+
+
+@endsection diff --git a/Modules/CCMS/resources/views/franchise/partials/_form.blade.php b/Modules/CCMS/resources/views/franchise/partials/_form.blade.php new file mode 100644 index 0000000..d2b7a04 --- /dev/null +++ b/Modules/CCMS/resources/views/franchise/partials/_form.blade.php @@ -0,0 +1,71 @@ +
+
+
+
+
+
+ {{ html()->label('Name')->class('form-label') }} + {{ html()->span('*')->class('text-danger') }} + {{ html()->text('title')->class('form-control')->placeholder('Enter Name')->required() }} + {{ html()->div('Name is required')->class('invalid-feedback') }} +
+ +
+ {{ html()->label('Designation')->class('form-label') }} + {{ html()->text('designation')->class('form-control')->placeholder('Enter Designation') }} +
+ +
+ {{ html()->label('Company')->class('form-label') }} + {{ html()->text('company')->class('form-control')->placeholder('Enter Company') }} +
+ +
+ {{ html()->label('Branch')->class('form-label')->for('branch_id') }} + {{ html()->select('branch_id', $branchOptions)->class('form-select choices-select')->placeholder('Select') }} +
+ +
+ {{ html()->label('Comment')->class('form-label')->for('description') }} + {{ html()->span('*')->class('text-danger') }} + {{ html()->textarea('description')->class('form-control')->rows(10) }} +
+
+
+
+
+ +
+
+
+
Publish
+
+
+
+
+ {{ html()->select('status', config('constants.page_status_options'))->class('form-select choices-select ') }} +
+
+
+ + + +
+ + +
+ +
diff --git a/Modules/CCMS/resources/views/newsletter/create.blade.php b/Modules/CCMS/resources/views/newsletter/create.blade.php new file mode 100644 index 0000000..b386130 --- /dev/null +++ b/Modules/CCMS/resources/views/newsletter/create.blade.php @@ -0,0 +1,14 @@ +@extends('layouts.app') +@section('content') +
+ + + + {{ html()->form('POST')->route('testimonial.store')->class(['needs-validation'])->attributes(['enctype' => 'multipart/form-data', 'novalidate'])->open() }} + + @include('ccms::testimonial.partials._form') + + {{ html()->form()->close() }} + +
+@endsection diff --git a/Modules/CCMS/resources/views/newsletter/datatable/action.blade.php b/Modules/CCMS/resources/views/newsletter/datatable/action.blade.php new file mode 100644 index 0000000..ab5049c --- /dev/null +++ b/Modules/CCMS/resources/views/newsletter/datatable/action.blade.php @@ -0,0 +1,8 @@ +
+ + + + + +
diff --git a/Modules/CCMS/resources/views/newsletter/edit.blade.php b/Modules/CCMS/resources/views/newsletter/edit.blade.php new file mode 100644 index 0000000..5d96439 --- /dev/null +++ b/Modules/CCMS/resources/views/newsletter/edit.blade.php @@ -0,0 +1,14 @@ +@extends('layouts.app') +@section('content') +
+ + + + {{ html()->modelForm($testimonial, 'PUT')->route('testimonial.update', $testimonial->id)->class(['needs-validation'])->attributes(['novalidate'])->open() }} + + @include('ccms::testimonial.partials._form') + + {{ html()->form()->close() }} + +
+@endsection diff --git a/Modules/CCMS/resources/views/newsletter/index.blade.php b/Modules/CCMS/resources/views/newsletter/index.blade.php new file mode 100644 index 0000000..9f7a0a3 --- /dev/null +++ b/Modules/CCMS/resources/views/newsletter/index.blade.php @@ -0,0 +1,33 @@ +@extends('layouts.app') +@section('content') +
+ +
+
+
{{ $title }}
+
+
+ @php + $columns = [ + [ + 'title' => 'S.N', + 'data' => 'DT_RowIndex', + 'name' => 'DT_RowIndex', + 'orderable' => false, + 'searchable' => false, + 'sortable' => false, + ], + ['title' => 'Email', 'data' => 'email', 'name' => 'email'], + [ + 'title' => 'Action', + 'data' => 'action', + 'orderable' => false, + 'searchable' => false, + ], + ]; + @endphp + +
+
+
+@endsection diff --git a/Modules/CCMS/resources/views/newsletter/partials/_form.blade.php b/Modules/CCMS/resources/views/newsletter/partials/_form.blade.php new file mode 100644 index 0000000..d2b7a04 --- /dev/null +++ b/Modules/CCMS/resources/views/newsletter/partials/_form.blade.php @@ -0,0 +1,71 @@ +
+
+
+
+
+
+ {{ html()->label('Name')->class('form-label') }} + {{ html()->span('*')->class('text-danger') }} + {{ html()->text('title')->class('form-control')->placeholder('Enter Name')->required() }} + {{ html()->div('Name is required')->class('invalid-feedback') }} +
+ +
+ {{ html()->label('Designation')->class('form-label') }} + {{ html()->text('designation')->class('form-control')->placeholder('Enter Designation') }} +
+ +
+ {{ html()->label('Company')->class('form-label') }} + {{ html()->text('company')->class('form-control')->placeholder('Enter Company') }} +
+ +
+ {{ html()->label('Branch')->class('form-label')->for('branch_id') }} + {{ html()->select('branch_id', $branchOptions)->class('form-select choices-select')->placeholder('Select') }} +
+ +
+ {{ html()->label('Comment')->class('form-label')->for('description') }} + {{ html()->span('*')->class('text-danger') }} + {{ html()->textarea('description')->class('form-control')->rows(10) }} +
+
+
+
+
+ +
+
+
+
Publish
+
+
+
+
+ {{ html()->select('status', config('constants.page_status_options'))->class('form-select choices-select ') }} +
+
+
+ + + +
+ + +
+ +
diff --git a/Modules/CCMS/routes/web.php b/Modules/CCMS/routes/web.php index bf7bfe3..e25e4f3 100644 --- a/Modules/CCMS/routes/web.php +++ b/Modules/CCMS/routes/web.php @@ -10,9 +10,11 @@ use Modules\CCMS\Http\Controllers\CountryController; use Modules\CCMS\Http\Controllers\EnquiryController; use Modules\CCMS\Http\Controllers\FaqCategoryController; use Modules\CCMS\Http\Controllers\FaqController; +use Modules\CCMS\Http\Controllers\FranchiseController; use Modules\CCMS\Http\Controllers\GalleryCategoryController; use Modules\CCMS\Http\Controllers\GalleryController; use Modules\CCMS\Http\Controllers\InstitutionController; +use Modules\CCMS\Http\Controllers\NewsletterController; use Modules\CCMS\Http\Controllers\PageController; use Modules\CCMS\Http\Controllers\PartnerController; use Modules\CCMS\Http\Controllers\PopupController; @@ -124,5 +126,8 @@ Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/ Route::get('enquiry/mark-as-read/{id}', [EnquiryController::class, 'markAsRead'])->name('enquiry.markAsRead'); Route::resource('enquiry', EnquiryController::class)->names('enquiry')->only(['index', 'store', 'destroy']); + Route::resource('franchise', FranchiseController::class)->names('franchise')->only(['index', 'store', 'destroy']); + Route::resource('newsletter', NewsletterController::class)->names('newsletter')->only(['index', 'store', 'destroy']); + Route::resource('counselor', CounselorController::class)->names('counselor')->only(['index', 'store', 'destroy']); }); diff --git a/config/sidebar.php b/config/sidebar.php index 7f6bf0c..3afc673 100644 --- a/config/sidebar.php +++ b/config/sidebar.php @@ -45,6 +45,38 @@ return [ 'can' => ['menu.index'], ], + [ + 'text' => 'Enquiries', + 'icon' => 'ri-cellphone-line', + 'module' => 'CCMS', + 'submenu' => [ + + [ + 'text' => 'Enquiry', + 'url' => 'admin/enquiry', + 'can' => ['enquiry.index'], + ], + + [ + 'text' => 'Counsellor Request', + 'url' => 'admin/counselor', + 'can' => ['counselor.index'], + ], + + [ + 'text' => 'Franchise Request', + 'url' => 'admin/franchise', + // 'can' => ['franchise.index'], + ], + + [ + 'text' => 'Newsletter', + 'url' => 'admin/newsletter', + // 'can' => ['newsletter.index'], + ], + ], + ], + [ 'text' => 'Offer Popup', 'url' => 'admin/popup', @@ -181,21 +213,7 @@ return [ ], ], - [ - 'text' => 'Enquiry', - 'url' => 'admin/enquiry', - 'icon' => ' ri-cellphone-line', - 'module' => 'CCMS', - 'can' => ['enquiry.index'], - ], - [ - 'text' => 'Counsellor Request', - 'url' => 'admin/counselor', - 'icon' => ' ri-cellphone-line', - 'module' => 'CCMS', - 'can' => ['counselor.index'], - ], [ 'text' => 'Course Finder', diff --git a/resources/views/client/raffles/layouts/app.blade.php b/resources/views/client/raffles/layouts/app.blade.php index 66c5dce..b6a868a 100644 --- a/resources/views/client/raffles/layouts/app.blade.php +++ b/resources/views/client/raffles/layouts/app.blade.php @@ -219,6 +219,86 @@ }); + + + +