diff --git a/Modules/CostCalculator/app/Http/Controllers/.gitkeep b/Modules/CostCalculator/app/Http/Controllers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/app/Http/Controllers/CostCalculatorController.php b/Modules/CostCalculator/app/Http/Controllers/CostCalculatorController.php
new file mode 100644
index 0000000..9fdd8b5
--- /dev/null
+++ b/Modules/CostCalculator/app/Http/Controllers/CostCalculatorController.php
@@ -0,0 +1,246 @@
+costCalculatorService = $costCalculatorService;
+ }
+ /**
+ * Display a listing of the resource.
+ */
+ public function index(Request $request)
+ {
+ $data['title'] = 'Cost Calculator List';
+ $data['costs'] = $this->costCalculatorService->findAll($request);
+ $data['countryOptions'] = Country::where('status', 1)->pluck('title', 'id');
+ $data['programLevelOptions'] = ProgramLevel::where('status', 1)->pluck('title', 'id');
+ $data['programOptions'] = Program::where('status', 1)->pluck('title', 'id');
+ $data['livingStatusOptions'] = config('constants.living_status');
+
+ return view('costCalculator::cost.index', $data);
+ }
+
+ /**
+ * Show the form for creating a new resource.
+ */
+ public function create()
+ {
+ $data['title'] = 'Program Create';
+ $data['editable'] = false;
+ $data['intakeOptions'] = Program::INTAKE;
+ $data['institutionOptions'] = Institution::where('status', 1)->pluck('title', 'id');
+ $data['programLevelOptions'] = ProgramLevel::where('status', 1)->pluck('title', 'id');
+ $data['testOptions'] = Test::where('status', 1)->where('parent_id', null)->pluck('title', 'id');
+
+ return view('coursefinder::program.create', $data);
+ }
+
+ /**
+ * Store a newly created resource in storage.
+ */
+ public function store(Request $request)
+ {
+
+ $request->validate([
+ 'title' => 'required',
+ ]);
+
+ $input = $request->except(['prof_test_accepted']);
+
+ DB::transaction(function () use ($input, $request) {
+
+ $program = Program::create($input);
+
+ $attachData = [];
+
+ foreach ($request->prof_test_accepted as $item) {
+ $attachData[$item['test_id']] = [
+ 'min_score' => $item['min_score'],
+ 'band_score' => $item['band_score'],
+ ];
+ }
+
+ $program->tests()->sync($attachData);
+
+ flash()->success('Program has been created!');
+ });
+
+ return redirect()->route('program.index');
+ }
+
+ /**
+ * Show the specified resource.
+ */
+ public function show($id)
+ {
+ $data['title'] = 'View Program';
+ $data['program'] = Program::findOrFail($id);
+ $data['intakeOptions'] = Program::INTAKE;
+ return view('coursefinder::program.show', $data);
+ }
+
+ /**
+ * Show the form for editing the specified resource.
+ */
+ public function edit($id)
+ {
+ $data['title'] = 'Edit Program';
+ $data['editable'] = true;
+ $data['program'] = Program::findOrFail($id);
+ $data['intakeOptions'] = Program::INTAKE;
+ $data['institutionOptions'] = Institution::where('status', 1)->pluck('title', 'id');
+ $data['programLevelOptions'] = ProgramLevel::where('status', 1)->pluck('title', 'id');
+ $data['testOptions'] = Test::where('status', 1)->where('parent_id', null)->pluck('title', 'id');
+ $data['coopOptions'] = Coop::where('status', 1)->pluck('title', 'id');
+ $data['requiredDocumentOptions'] = RequiredDocument::where('status', 1)->pluck('title', 'id');
+ return view('coursefinder::program.edit', $data);
+ }
+
+ /**
+ * Update the specified resource in storage.
+ */
+ public function update(Request $request, $id)
+ {
+ $input = $request->except(['prof_test_accepted']);
+
+ DB::transaction(function () use ($input, $request, $id) {
+ $program = Program::findOrFail($id);
+ $program->update($input);
+
+ $attachData = [];
+
+ foreach ($request->prof_test_accepted as $item) {
+ $attachData[$item['test_id']] = [
+ 'min_score' => $item['min_score'],
+ 'band_score' => $item['band_score'],
+ ];
+ }
+
+ $program->tests()->sync($attachData);
+ });
+
+ flash()->success('program has been updated!');
+
+ return redirect()->route('program.index')->withSuccess('Program has been updated!');
+ }
+
+ /**
+ * Remove the specified resource from storage.
+ */
+ public function destroy($id)
+ {
+ try {
+ $program = Program::findOrFail($id);
+ $program->delete();
+
+ flash()->success('Program has been deleted!');
+ } catch (\Throwable $th) {
+ flash()->error($th->getMessage());
+ }
+ return response()->json(['status' => 200, 'message' => 'Program has been deleted!'], 200);
+ }
+
+ public function getProgramByInstitution(Request $request)
+ {
+ try {
+ $program = Program::where(['institution_id' => $request->institution_id])
+ ->select('id', 'title')
+ ->get();
+ return response()->json([
+ 'status' => true,
+ 'data' => $program,
+ 'msg' => 'Fetch',
+ ], 200);
+ } catch (\Throwable $th) {
+ return response()->json([
+ 'status' => false,
+ 'msg' => $th->getMessage(),
+ ], 500);
+ }
+ }
+
+ public function import(Request $request)
+ {
+ DB::beginTransaction();
+ try {
+ Excel::import(new ProgramImport(), $request->file('file')->store('temp'));
+ DB::commit();
+ return redirect()->back()->with('success', "Upload Succesfully");
+ } catch (\Throwable $th) {
+ DB::rollback();
+ return redirect()->back()->with('error', $th->getMessage());
+ }
+ }
+
+ public function getCoursesList(Request $request)
+ {
+ $data['intakes'] = Program::INTAKE;
+
+ $query = Program::query();
+
+ if ($request->filled('countries_id')) {
+ $query->whereRelation('institution', 'countries_id', $request->countries_id);
+ }
+
+ if ($request->filled('institution_id')) {
+ $query->where('institutions_id', $request->institution_id);
+ }
+
+ if ($request->filled('search')) {
+ $query->where('title', 'like', "%{$request->search}%");
+ }
+
+ if ($request->filled('programlevels_id')) {
+ $query->where('programlevels_id', $request->programlevels_id);
+ }
+
+ if ($request->filled('intake_id')) {
+ $query->whereJsonContains('intakes', $request->intake_id);
+ }
+
+ if ($request->filled('preffered_location')) {
+ $query->where('location', 'like', "%{$request->preffered_location}%");
+ }
+
+ if ($request->filled('service_id')) {
+ $query->whereRelation('services', 'service_id', '=', $request->service_id);
+
+ if ($request->filled('min_score')) {
+ $query->whereRelation('services', 'min_score', '<=', $request->min_score);
+ }
+
+ if ($request->filled('max_score')) {
+ $query->whereRelation('services', 'band_score', '<=', $request->max_score);
+ }
+ }
+
+ $data['courses'] = $query
+ ->orderBy('title', 'asc')
+ ->paginate(10)
+ ->withQueryString();
+
+ $queryCount = $data['courses']->total();
+
+ if ($request->ajax()) {
+ $view = view('client.raffles.pages.course.list', $data)->render();
+ return response()->json(['html' => $view, 'queryCount' => $queryCount]);
+ }
+ }
+}
diff --git a/Modules/CostCalculator/app/Models/CostCalculator.php b/Modules/CostCalculator/app/Models/CostCalculator.php
new file mode 100644
index 0000000..3465741
--- /dev/null
+++ b/Modules/CostCalculator/app/Models/CostCalculator.php
@@ -0,0 +1,44 @@
+ 'object',
+ 'accomodation_cost' => 'object',
+ 'onetime_cost' => 'object',
+ 'other_services' => 'object',
+ ];
+
+ public function institution()
+ {
+ return $this->belongsTo(Country::class, 'country_id');
+ }
+
+ public function programLevel()
+ {
+ return $this->belongsTo(ProgramLevel::class, 'programlevel_id');
+ }
+
+ public function program()
+ {
+ return $this->belongsTo(Program::class, 'program_id');
+ }
+}
diff --git a/Modules/CostCalculator/app/Models/Scopes/.gitkeep b/Modules/CostCalculator/app/Models/Scopes/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/app/Providers/.gitkeep b/Modules/CostCalculator/app/Providers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/app/Providers/CostCalculatorServiceProvider.php b/Modules/CostCalculator/app/Providers/CostCalculatorServiceProvider.php
new file mode 100644
index 0000000..8847a29
--- /dev/null
+++ b/Modules/CostCalculator/app/Providers/CostCalculatorServiceProvider.php
@@ -0,0 +1,135 @@
+registerCommands();
+ $this->registerCommandSchedules();
+ $this->registerTranslations();
+ $this->registerConfig();
+ $this->registerViews();
+ $this->loadMigrationsFrom(module_path($this->name, 'database/migrations'));
+ }
+
+ /**
+ * Register the service provider.
+ */
+ public function register(): void
+ {
+ $this->app->register(EventServiceProvider::class);
+ $this->app->register(RouteServiceProvider::class);
+ }
+
+ /**
+ * Register commands in the format of Command::class
+ */
+ protected function registerCommands(): void
+ {
+ // $this->commands([]);
+ }
+
+ /**
+ * Register command Schedules.
+ */
+ protected function registerCommandSchedules(): void
+ {
+ // $this->app->booted(function () {
+ // $schedule = $this->app->make(Schedule::class);
+ // $schedule->command('inspire')->hourly();
+ // });
+ }
+
+ /**
+ * Register translations.
+ */
+ public function registerTranslations(): void
+ {
+ $langPath = resource_path('lang/modules/'.$this->nameLower);
+
+ if (is_dir($langPath)) {
+ $this->loadTranslationsFrom($langPath, $this->nameLower);
+ $this->loadJsonTranslationsFrom($langPath);
+ } else {
+ $this->loadTranslationsFrom(module_path($this->name, 'lang'), $this->nameLower);
+ $this->loadJsonTranslationsFrom(module_path($this->name, 'lang'));
+ }
+ }
+
+ /**
+ * Register config.
+ */
+ protected function registerConfig(): void
+ {
+ $relativeConfigPath = config('modules.paths.generator.config.path');
+ $configPath = module_path($this->name, $relativeConfigPath);
+
+ if (is_dir($configPath)) {
+ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($configPath));
+
+ foreach ($iterator as $file) {
+ if ($file->isFile() && $file->getExtension() === 'php') {
+ $relativePath = str_replace($configPath . DIRECTORY_SEPARATOR, '', $file->getPathname());
+ $configKey = $this->nameLower . '.' . str_replace([DIRECTORY_SEPARATOR, '.php'], ['.', ''], $relativePath);
+ $key = ($relativePath === 'config.php') ? $this->nameLower : $configKey;
+
+ $this->publishes([$file->getPathname() => config_path($relativePath)], 'config');
+ $this->mergeConfigFrom($file->getPathname(), $key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Register views.
+ */
+ public function registerViews(): void
+ {
+ $viewPath = resource_path('views/modules/'.$this->nameLower);
+ $sourcePath = module_path($this->name, 'resources/views');
+
+ $this->publishes([$sourcePath => $viewPath], ['views', $this->nameLower.'-module-views']);
+
+ $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->nameLower);
+
+ $componentNamespace = $this->module_namespace($this->name, $this->app_path(config('modules.paths.generator.component-class.path')));
+ Blade::componentNamespace($componentNamespace, $this->nameLower);
+ }
+
+ /**
+ * Get the services provided by the provider.
+ */
+ public function provides(): array
+ {
+ return [];
+ }
+
+ private function getPublishableViewPaths(): array
+ {
+ $paths = [];
+ foreach (config('view.paths') as $path) {
+ if (is_dir($path.'/modules/'.$this->nameLower)) {
+ $paths[] = $path.'/modules/'.$this->nameLower;
+ }
+ }
+
+ return $paths;
+ }
+}
diff --git a/Modules/CostCalculator/app/Providers/EventServiceProvider.php b/Modules/CostCalculator/app/Providers/EventServiceProvider.php
new file mode 100644
index 0000000..cbd8e97
--- /dev/null
+++ b/Modules/CostCalculator/app/Providers/EventServiceProvider.php
@@ -0,0 +1,30 @@
+>
+ */
+ protected $listen = [];
+
+ /**
+ * Indicates if events should be discovered.
+ *
+ * @var bool
+ */
+ protected static $shouldDiscoverEvents = true;
+
+ /**
+ * Configure the proper event listeners for email verification.
+ */
+ protected function configureEmailVerification(): void
+ {
+ //
+ }
+}
diff --git a/Modules/CostCalculator/app/Providers/RouteServiceProvider.php b/Modules/CostCalculator/app/Providers/RouteServiceProvider.php
new file mode 100644
index 0000000..dfafb7f
--- /dev/null
+++ b/Modules/CostCalculator/app/Providers/RouteServiceProvider.php
@@ -0,0 +1,50 @@
+mapApiRoutes();
+ $this->mapWebRoutes();
+ }
+
+ /**
+ * Define the "web" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ */
+ protected function mapWebRoutes(): void
+ {
+ Route::middleware('web')->group(module_path($this->name, '/routes/web.php'));
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ *
+ * These routes are typically stateless.
+ */
+ protected function mapApiRoutes(): void
+ {
+ Route::middleware('api')->prefix('api')->name('api.')->group(module_path($this->name, '/routes/api.php'));
+ }
+}
diff --git a/Modules/CostCalculator/app/Services/.gitkeep b/Modules/CostCalculator/app/Services/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/app/Services/CostCalculatorService.php b/Modules/CostCalculator/app/Services/CostCalculatorService.php
new file mode 100644
index 0000000..39e30c2
--- /dev/null
+++ b/Modules/CostCalculator/app/Services/CostCalculatorService.php
@@ -0,0 +1,53 @@
+filled('country_id')) {
+ $query->whereRelation('institution', 'country_id', $request->country_id);
+ }
+
+ if ($request->filled('institution_id')) {
+ $query->where("institution_id", $request->institution_id);
+ }
+
+ if ($request->filled('programlevel_id')) {
+ $query->where("programlevel_id", $request->programlevel_id);
+ }
+
+ if ($request->filled('intake_id')) {
+ $intakeId = $request->intake_id;
+ $query->whereJsonContains('intakes', $intakeId);
+ }
+
+ if ($request->filled('status')) {
+ $query->where('status', $request->status);
+ }
+
+ if ($request->filled('search')) {
+ $search = $request->search;
+ $query->where('title', 'like', "%{$search}%");
+ }
+
+ if ($request->filled('location')) {
+ $location = $request->location;
+ $query->where('location', 'like', "%{$location}%");
+ }
+ })->latest()->paginate(10)->withQueryString();
+ }
+
+ public function pluck(callable $query = null)
+ {
+ $baseQuery = CostCalculator::query();
+ if (is_callable($query)) {
+ $query($baseQuery);
+ }
+ return $baseQuery->pluck('title', 'id');
+ }
+}
diff --git a/Modules/CostCalculator/composer.json b/Modules/CostCalculator/composer.json
new file mode 100644
index 0000000..b1ae184
--- /dev/null
+++ b/Modules/CostCalculator/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "nwidart/costcalculator",
+ "description": "",
+ "authors": [
+ {
+ "name": "Nicolas Widart",
+ "email": "n.widart@gmail.com"
+ }
+ ],
+ "extra": {
+ "laravel": {
+ "providers": [],
+ "aliases": {
+
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Modules\\CostCalculator\\": "app/",
+ "Modules\\CostCalculator\\Database\\Factories\\": "database/factories/",
+ "Modules\\CostCalculator\\Database\\Seeders\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\CostCalculator\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/Modules/CostCalculator/config/.gitkeep b/Modules/CostCalculator/config/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/config/config.php b/Modules/CostCalculator/config/config.php
new file mode 100644
index 0000000..dab8c60
--- /dev/null
+++ b/Modules/CostCalculator/config/config.php
@@ -0,0 +1,5 @@
+ 'CostCalculator',
+];
diff --git a/Modules/CostCalculator/database/factories/.gitkeep b/Modules/CostCalculator/database/factories/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/database/migrations/.gitkeep b/Modules/CostCalculator/database/migrations/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/database/migrations/2025_08_13_102211_create_cost_calculators_table.php b/Modules/CostCalculator/database/migrations/2025_08_13_102211_create_cost_calculators_table.php
new file mode 100644
index 0000000..046d2a4
--- /dev/null
+++ b/Modules/CostCalculator/database/migrations/2025_08_13_102211_create_cost_calculators_table.php
@@ -0,0 +1,38 @@
+id();
+ $table->unsignedInteger('country_id')->nullable();
+ $table->unsignedInteger('programlevel_id')->nullable();
+ $table->unsignedInteger('program_id')->nullable();
+ $table->unsignedInteger('living_status_id')->nullable();
+ $table->json('living_cost')->nullable();
+ $table->json('accomodation_cost')->nullable();
+ $table->json('onetime_cost')->nullable();
+ $table->json('other_services')->nullable();
+ $table->unsignedInteger('createdby')->nullable();
+ $table->unsignedInteger('updatedby')->nullable();
+ $table->boolean('status')->default(1);
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('cost_calculators');
+ }
+};
diff --git a/Modules/CostCalculator/database/seeders/.gitkeep b/Modules/CostCalculator/database/seeders/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/database/seeders/CostCalculatorDatabaseSeeder.php b/Modules/CostCalculator/database/seeders/CostCalculatorDatabaseSeeder.php
new file mode 100644
index 0000000..dffd91c
--- /dev/null
+++ b/Modules/CostCalculator/database/seeders/CostCalculatorDatabaseSeeder.php
@@ -0,0 +1,16 @@
+call([]);
+ }
+}
diff --git a/Modules/CostCalculator/module.json b/Modules/CostCalculator/module.json
new file mode 100644
index 0000000..72a6482
--- /dev/null
+++ b/Modules/CostCalculator/module.json
@@ -0,0 +1,11 @@
+{
+ "name": "CostCalculator",
+ "alias": "costcalculator",
+ "description": "",
+ "keywords": [],
+ "priority": 0,
+ "providers": [
+ "Modules\\CostCalculator\\Providers\\CostCalculatorServiceProvider"
+ ],
+ "files": []
+}
diff --git a/Modules/CostCalculator/package.json b/Modules/CostCalculator/package.json
new file mode 100644
index 0000000..d6fbfc8
--- /dev/null
+++ b/Modules/CostCalculator/package.json
@@ -0,0 +1,15 @@
+{
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build"
+ },
+ "devDependencies": {
+ "axios": "^1.1.2",
+ "laravel-vite-plugin": "^0.7.5",
+ "sass": "^1.69.5",
+ "postcss": "^8.3.7",
+ "vite": "^4.0.0"
+ }
+}
diff --git a/Modules/CostCalculator/resources/assets/js/app.js b/Modules/CostCalculator/resources/assets/js/app.js
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/resources/assets/sass/app.scss b/Modules/CostCalculator/resources/assets/sass/app.scss
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/resources/views/.gitkeep b/Modules/CostCalculator/resources/views/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/resources/views/cost/create.blade.php b/Modules/CostCalculator/resources/views/cost/create.blade.php
new file mode 100644
index 0000000..50dbc42
--- /dev/null
+++ b/Modules/CostCalculator/resources/views/cost/create.blade.php
@@ -0,0 +1,10 @@
+@extends('layouts.app')
+@section('content')
+
+
+
+ {{ html()->form('POST')->route('costCalculator.store')->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data', 'onkeydown' => "return event.key != 'Enter';"])->open() }}
+ @include('costCalculator::cost.partials.form')
+ {{ html()->form()->close() }}
+
+@endsection
diff --git a/Modules/CostCalculator/resources/views/cost/edit.blade.php b/Modules/CostCalculator/resources/views/cost/edit.blade.php
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/resources/views/cost/index.blade.php b/Modules/CostCalculator/resources/views/cost/index.blade.php
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/resources/views/cost/partials/form.blade.php b/Modules/CostCalculator/resources/views/cost/partials/form.blade.php
new file mode 100644
index 0000000..0f7e25d
--- /dev/null
+++ b/Modules/CostCalculator/resources/views/cost/partials/form.blade.php
@@ -0,0 +1,326 @@
+
+
+
+
+
+
+
+ {{ html()->label('Country')->class('form-label') }}
+ {{ html()->span('*')->class('text-danger') }}
+ {{ html()->select('country_id', $countryOptions)->placeholder('Select')->class('form-select choices-select')->required() }}
+ {{ html()->div('Please select country')->class('invalid-feedback') }}
+
+
+
+ {{ html()->label('Program Level')->class('form-label')->for('programlevel_id') }}
+ {{ html()->span('*')->class('text-danger') }}
+ {{ html()->select('programlevel_id', $programLevelOptions)->placeholder('Select')->class('form-select choices-select')->required() }}
+ {{ html()->div('Please select program level')->class('invalid-feedback') }}
+
+
+
+ {{ html()->label('Living Status')->class('form-label')->for('institution_id') }}
+ {{ html()->span('*')->class('text-danger') }}
+ {{ html()->select('living_status_id', $livingStatusOptions)->placeholder('Select')->class('form-select choices-select')->required() }}
+ {{ html()->div('Please select Living Status')->class('invalid-feedback') }}
+
+
+
+ {{ html()->label('Program')->class('form-label')->for('program_id') }}
+ {{ html()->span('*')->class('text-danger') }}
+ {{ html()->select('program_id', $programOptions)->placeholder('Select')->class('form-select choices-select')->required() }}
+ {{ html()->div('Please select program')->class('invalid-feedback') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Monthly |
+ Yearly |
+ |
+
+
+
+ @if ($editable)
+ @if ($program->level)
+
+ @forelse ($program->level as $key => $item)
+ @include('coursefinder::program.partials.qualification-form', [
+ 'numInc' => $key,
+ 'value' => $item,
+ ])
+ @empty
+ @endforelse
+ @else
+ @include('coursefinder::program.partials.qualification-form', [
+ 'numInc' => 0,
+ ])
+
+ @endif
+ @else
+ @include('coursefinder::program.partials.qualification-form', [
+ 'numInc' => 0,
+ ])
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Monthly |
+ Yearly |
+ |
+
+
+
+ @if ($editable)
+ @forelse ($program->tests as $key => $item)
+ @include('coursefinder::program.partials.proficiency-form', [
+ 'numInc' => $key,
+ 'value' => $item,
+ ])
+ @empty
+ @include('coursefinder::program.partials.proficiency-form', [
+ 'numInc' => 0,
+ ])
+ @endforelse
+ @else
+ @include('coursefinder::program.partials.proficiency-form', [
+ 'numInc' => 0,
+ ])
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Visa |
+ Biometrics |
+ Sevis |
+ Application |
+ |
+
+
+
+ @if ($editable)
+ @if ($program->fee_breakdown)
+ @forelse ($program->fee_breakdown as $key => $item)
+ @include('coursefinder::program.partials.feeBreakdown', [
+ 'numInc' => $key,
+ 'value' => $item,
+ ])
+ @empty
+ @endforelse
+ @else
+ @include('coursefinder::program.partials.feeBreakdown', [
+ 'numInc' => 0,
+ ])
+
+ @endif
+ @else
+ @include('coursefinder::program.partials.feeBreakdown', [
+ 'numInc' => 0,
+ ])
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Flight Ticket |
+ Health Insurance |
+ Extra |
+ |
+
+
+
+ @if ($editable)
+ @if ($program->course_module)
+ @forelse ($program->course_module as $key => $item)
+ @include('coursefinder::program.partials.courseModule', [
+ 'numInc' => $key,
+ 'value' => $item,
+ ])
+ @empty
+ @endforelse
+ @else
+ @include('coursefinder::program.partials.courseModule', [
+ 'numInc' => 0,
+ ])
+
+ @endif
+ @else
+ @include('coursefinder::program.partials.courseModule', [
+ 'numInc' => 0,
+ ])
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+@push('js')
+
+@endpush
diff --git a/Modules/CostCalculator/resources/views/cost/show.blade.php b/Modules/CostCalculator/resources/views/cost/show.blade.php
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/resources/views/index.blade.php b/Modules/CostCalculator/resources/views/index.blade.php
new file mode 100644
index 0000000..e1eaa06
--- /dev/null
+++ b/Modules/CostCalculator/resources/views/index.blade.php
@@ -0,0 +1,7 @@
+@extends('costcalculator::layouts.master')
+
+@section('content')
+ Hello World
+
+ Module: {!! config('costcalculator.name') !!}
+@endsection
diff --git a/Modules/CostCalculator/resources/views/layouts/master.blade.php b/Modules/CostCalculator/resources/views/layouts/master.blade.php
new file mode 100644
index 0000000..7d137fd
--- /dev/null
+++ b/Modules/CostCalculator/resources/views/layouts/master.blade.php
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+ CostCalculator Module - {{ config('app.name', 'Laravel') }}
+
+
+
+
+
+
+
+
+
+ {{-- Vite CSS --}}
+ {{-- {{ module_vite('build-costcalculator', 'resources/assets/sass/app.scss', storage_path('vite.hot')) }} --}}
+
+
+
+ @yield('content')
+
+ {{-- Vite JS --}}
+ {{-- {{ module_vite('build-costcalculator', 'resources/assets/js/app.js', storage_path('vite.hot')) }} --}}
+
diff --git a/Modules/CostCalculator/routes/.gitkeep b/Modules/CostCalculator/routes/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Modules/CostCalculator/routes/api.php b/Modules/CostCalculator/routes/api.php
new file mode 100644
index 0000000..0262fce
--- /dev/null
+++ b/Modules/CostCalculator/routes/api.php
@@ -0,0 +1,19 @@
+prefix('v1')->group(function () {
+ Route::apiResource('costcalculator', CostCalculatorController::class)->names('costcalculator');
+});
diff --git a/Modules/CostCalculator/routes/web.php b/Modules/CostCalculator/routes/web.php
new file mode 100644
index 0000000..b403665
--- /dev/null
+++ b/Modules/CostCalculator/routes/web.php
@@ -0,0 +1,19 @@
+names('costcalculator');
+});
diff --git a/Modules/CostCalculator/vite.config.js b/Modules/CostCalculator/vite.config.js
new file mode 100644
index 0000000..34a4241
--- /dev/null
+++ b/Modules/CostCalculator/vite.config.js
@@ -0,0 +1,57 @@
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+import { readdirSync, statSync } from 'fs';
+import { join,relative,dirname } from 'path';
+import { fileURLToPath } from 'url';
+
+export default defineConfig({
+ build: {
+ outDir: '../../public/build-costcalculator',
+ emptyOutDir: true,
+ manifest: true,
+ },
+ plugins: [
+ laravel({
+ publicDirectory: '../../public',
+ buildDirectory: 'build-costcalculator',
+ input: [
+ __dirname + '/resources/assets/sass/app.scss',
+ __dirname + '/resources/assets/js/app.js'
+ ],
+ refresh: true,
+ }),
+ ],
+});
+// Scen all resources for assets file. Return array
+//function getFilePaths(dir) {
+// const filePaths = [];
+//
+// function walkDirectory(currentPath) {
+// const files = readdirSync(currentPath);
+// for (const file of files) {
+// const filePath = join(currentPath, file);
+// const stats = statSync(filePath);
+// if (stats.isFile() && !file.startsWith('.')) {
+// const relativePath = 'Modules/CostCalculator/'+relative(__dirname, filePath);
+// filePaths.push(relativePath);
+// } else if (stats.isDirectory()) {
+// walkDirectory(filePath);
+// }
+// }
+// }
+//
+// walkDirectory(dir);
+// return filePaths;
+//}
+
+//const __filename = fileURLToPath(import.meta.url);
+//const __dirname = dirname(__filename);
+
+//const assetsDir = join(__dirname, 'resources/assets');
+//export const paths = getFilePaths(assetsDir);
+
+
+//export const paths = [
+// 'Modules/CostCalculator/resources/assets/sass/app.scss',
+// 'Modules/CostCalculator/resources/assets/js/app.js',
+//];
diff --git a/config/constants.php b/config/constants.php
index 481f437..ad4bfc9 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -78,4 +78,9 @@ return [
14 => 'Archived',
],
+ 'living_status'=> [
+ 1 => 'Alone',
+ 2 => 'With Spouse',
+ 3 => 'With Spouse and Child',
+ ]
];
diff --git a/modules_statuses.json b/modules_statuses.json
index 87133bc..1a2ed1d 100644
--- a/modules_statuses.json
+++ b/modules_statuses.json
@@ -17,5 +17,6 @@
"Admin": true,
"Drive": true,
"Sitemap": true,
- "Document": true
+ "Document": true,
+ "CostCalculator": true
}
\ No newline at end of file
diff --git a/public/raffles/assets/js/style.js b/public/raffles/assets/js/style.js
index 74a9426..ac5951a 100644
--- a/public/raffles/assets/js/style.js
+++ b/public/raffles/assets/js/style.js
@@ -584,16 +584,17 @@ document.addEventListener('keydown', e => {
});
+// cost calculator progress
// cost calculator progress
let currentStep = 1;
-const totalSteps = 5;
+const totalSteps = 7; // updated to match HTML
const monkey = document.getElementById('monkey').querySelector('img');
const monkeyContainer = document.getElementById('monkey');
-const nextBtn = document.querySelector('.next-btn button');
+const nextBtn = document.getElementById('nextBtn');
+const doneBtn = document.getElementById('doneBtn');
const bananalast = document.getElementById('b5');
-
const monkeyImages = [
"/raffles/assets/images/icons/monkey1.png",
"/raffles/assets/images/icons/monkey2.png",
@@ -608,33 +609,25 @@ nextBtn.addEventListener('click', () => {
if (currentStep < totalSteps) {
currentStep++;
- // Move monkey
+ // Calculate monkey position based on window width
+ let percent;
if (window.innerWidth <= 540) {
- const percent = ((currentStep - 1) / (totalSteps - 0.2)) * 100;
- monkeyContainer.style.left = percent + '%';
- }
- else if (window.innerWidth <= 768) {
- const percent = ((currentStep - 1) / (totalSteps - 0.3)) * 100;
- monkeyContainer.style.left = percent + '%';
- }
- else if (window.innerWidth <= 992) {
- const percent = ((currentStep - 1) / (totalSteps - 0.7)) * 100;
- monkeyContainer.style.left = percent + '%';
- }
- else if (window.innerWidth <= 1180) {
- const percent = ((currentStep - 1) / (totalSteps - 0.2)) * 100;
- monkeyContainer.style.left = percent + '%';
- }
- else {
- const percent = ((currentStep - 1) / (totalSteps - 0.5)) * 100;
- monkeyContainer.style.left = percent + '%';
+ percent = ((currentStep - 1) / (totalSteps - 0.2)) * 100;
+ } else if (window.innerWidth <= 768) {
+ percent = ((currentStep - 1) / (totalSteps - 0.3)) * 100;
+ } else if (window.innerWidth <= 992) {
+ percent = ((currentStep - 1) / (totalSteps - 0.7)) * 100;
+ } else if (window.innerWidth <= 1180) {
+ percent = ((currentStep - 1) / (totalSteps - 0.2)) * 100;
+ } else {
+ percent = ((currentStep - 1) / (totalSteps - 0.5)) * 100;
}
+ monkeyContainer.style.left = percent + '%';
-
- // Change monkey image
+ // Update monkey image
monkey.src = monkeyImages[currentStep - 1];
- // Update step content
+ // Switch step content
const currentContent = document.getElementById('step' + (currentStep - 1));
const nextContent = document.getElementById('step' + currentStep);
if (currentContent && nextContent) {
@@ -642,30 +635,29 @@ nextBtn.addEventListener('click', () => {
nextContent.classList.add('active');
}
- // At final step (Step 5), hide Next and show Done
+ // Show done button on last step
if (currentStep === totalSteps) {
nextBtn.style.display = 'none';
doneBtn.style.display = 'block';
}
- } w
+ }
});
+
doneBtn.addEventListener('click', () => {
bananalast.classList.add('active');
if (window.innerWidth <= 992) {
- // On mobile: show 7th image and move down
- monkey.src = monkeyImages[6]; // 7th image (index 6)
+ monkey.src = monkeyImages[6]; // last image
monkeyContainer.style.top = '142%';
- monkeyContainer.style.left = '40%'; // Optional: keep it centered or adjust as needed
+ monkeyContainer.style.left = '40%';
} else {
- // On desktop: show 6th image and move right
- monkey.src = monkeyImages[5]; // 6th image (index 5)
+ monkey.src = monkeyImages[5];
monkeyContainer.style.left = '110%';
- monkeyContainer.style.top = '-120%'; // Reset top if changed previously
+ monkeyContainer.style.top = '-120%';
}
});
-// Final monkey image
+
diff --git a/resources/views/client/raffles/pages/cost-calculator.blade.php b/resources/views/client/raffles/pages/cost-calculator.blade.php
index 495b753..a2af845 100644
--- a/resources/views/client/raffles/pages/cost-calculator.blade.php
+++ b/resources/views/client/raffles/pages/cost-calculator.blade.php
@@ -19,158 +19,263 @@