Compare commits
45 Commits
41cbf386e0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f9420643e | |||
| a2caa6f847 | |||
| 33219a4d88 | |||
| 9d98ad7a10 | |||
| 2f407d9530 | |||
| cf8844471b | |||
| fbcc3226fe | |||
| 597f9c111f | |||
| a5c3da9436 | |||
| 49c0c94ec9 | |||
| 68418d1205 | |||
| f41e77a3a7 | |||
| 73de3a69b9 | |||
| bb1e38d274 | |||
| 9bbd65eaaf | |||
| 0a9205ea8b | |||
| 22756f3f31 | |||
| 8139bcbad9 | |||
| 399099a802 | |||
| 45c2fe0485 | |||
| f58b69cc15 | |||
| c7360e254a | |||
| 604293aef4 | |||
| f1ec98e0d4 | |||
| 8209ea594a | |||
| 2df03900ee | |||
| 3d35977e57 | |||
| 67967c7def | |||
| e55e88fa62 | |||
| 82c9971289 | |||
| 4375ac1fc8 | |||
| 3cfa2e3513 | |||
| d3801506da | |||
| 32d35aa4c7 | |||
| 148a010f4d | |||
| aff90ceb86 | |||
| 11be2f2f03 | |||
| d4e8b7db60 | |||
| 01e67e5cb5 | |||
| d3bae105da | |||
| 5cc07b7371 | |||
| 4323698a94 | |||
| 665159612c | |||
| 8875266134 | |||
| 97096c3e31 |
@@ -1,17 +0,0 @@
|
||||
# .gitea/workflows/build.yaml
|
||||
name: Gitea Actions Demo
|
||||
run-name: ${{ github.actor }} is testing out Gitea Actions 🚀
|
||||
on: [push]
|
||||
jobs:
|
||||
Explore-Gitea-Actions:
|
||||
runs-on: linux-x64
|
||||
steps:
|
||||
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
|
||||
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
||||
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
|
||||
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||
- name: List files in the repository
|
||||
run: |
|
||||
ls ${{ github.workspace }}
|
||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||
27
.gitea/workflows/deploy.yml
Normal file
27
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
concurrency: production_environment
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: centos
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.1"
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install
|
||||
|
||||
- name: Deploy
|
||||
uses: deployphp/action@v1
|
||||
with:
|
||||
dep: deploy
|
||||
18
Taskfile.yml
Normal file
18
Taskfile.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
# https://taskfile.dev
|
||||
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
GREETING: Hello, World!
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "{{.GREETING}}"
|
||||
silent: true
|
||||
deploy:
|
||||
cmds:
|
||||
- vendor/bin/dep deploy
|
||||
build:
|
||||
cmds:
|
||||
- vendor/bin/dep build
|
||||
@@ -22,6 +22,10 @@ class CountryCodeController extends Controller
|
||||
return CountryCode::active("Y");
|
||||
}
|
||||
|
||||
public function codes()
|
||||
{
|
||||
return CountryCode::countryHash();
|
||||
}
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
|
||||
@@ -36,6 +36,7 @@ class CountryCompareController extends Controller
|
||||
$requests = Http::pool(fn (Pool $pool) => [
|
||||
CountryCode::all()->each(function ($countryCode) use ($pool, $ta_code) {
|
||||
$this->countries[] = $countryCode->country_name;
|
||||
Log::info('Getting page {url}', [ 'url' => $countryCode->search_url . $ta_code ] );
|
||||
return $pool->as($countryCode->country_name)->get($countryCode->search_url . $ta_code);
|
||||
})
|
||||
]);
|
||||
|
||||
14
app/Http/Controllers/CurrencyRatesController.php
Normal file
14
app/Http/Controllers/CurrencyRatesController.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\CurrencyRates;
|
||||
class CurrencyRatesController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return CurrencyRates::all();
|
||||
}
|
||||
|
||||
}
|
||||
17
app/Http/Controllers/IkeaProductsController.php
Normal file
17
app/Http/Controllers/IkeaProductsController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
use App\Models\IkeaProducts;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Client\Pool;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
|
||||
class IkeaProductsController extends Controller
|
||||
{
|
||||
public function search(Request $request, string $item, string $country = '')
|
||||
{
|
||||
return IkeaProducts::search($item, $country);
|
||||
}
|
||||
}
|
||||
65
app/Http/Controllers/ProductsCompareController.php
Normal file
65
app/Http/Controllers/ProductsCompareController.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\IkeaProducts;
|
||||
use Illuminate\Http\Client\Pool;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\CountryCode;
|
||||
use App\Models\CurrencyRates;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class ProductsCompareController extends Controller
|
||||
{
|
||||
public function compare(Request $request)
|
||||
{
|
||||
$codes = $request->input("codes");
|
||||
$countries = $request->input("countries");
|
||||
$currency = $request->input("currency");
|
||||
|
||||
Log::info("{codes} {countries}", ["codes" => $codes, "countries" => $countries]);
|
||||
|
||||
$codes = collect($codes);
|
||||
$countries = collect($countries);
|
||||
|
||||
if ($countries != null && count($countries)) {
|
||||
$hCountry = CountryCode::countryHash();
|
||||
$countries = $countries->map(function ($country) use ($hCountry) {
|
||||
return $hCountry[$country];
|
||||
});
|
||||
} else {
|
||||
$countries = [];
|
||||
}
|
||||
|
||||
$cHash = CountryCode::code_countryHash();
|
||||
if (is_array($codes) == false)
|
||||
$aCodes = [$codes['code']];
|
||||
else
|
||||
$aCodes = $codes->map(function ($code) {
|
||||
return $code['code'];
|
||||
});
|
||||
|
||||
$products = IkeaProducts::whereIn("code", $aCodes);
|
||||
if (count($countries)) $products->whereIn("country",$countries);
|
||||
$products = $products->get();
|
||||
|
||||
$currencyRates = CurrencyRates::rates2EUR("Y");
|
||||
if ($currency == "EUR") {
|
||||
$coef = 1;
|
||||
} else {
|
||||
$coef = floatval(CurrencyRates::where('currency',$currency)->first()->rate);
|
||||
}
|
||||
|
||||
$products = $products->map(function ($product) use ($currencyRates, $coef) {
|
||||
$product["salesPrice"] = round(floatval(($product["salesPrice"]) / $currencyRates[$product["country"]]) * $coef, 2);
|
||||
return $product;
|
||||
});
|
||||
Log::info("{products}", ["products" => $products]);
|
||||
return Inertia::render('IkeaRoot', [
|
||||
'products' => $products,
|
||||
'countryHash' => $cHash,
|
||||
]);
|
||||
}
|
||||
}
|
||||
30
app/Http/Controllers/Superuser/UserMenuController.php
Normal file
30
app/Http/Controllers/Superuser/UserMenuController.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Superuser;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Menus\Menu as MenusMenu;
|
||||
use App\Models\Menu;
|
||||
use App\Models\Permission;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use SplFileInfo;
|
||||
use Throwable;
|
||||
|
||||
class UserMenuController extends MenuController
|
||||
{
|
||||
public function get()
|
||||
{
|
||||
return Menu::with(['childs', 'permissions'])
|
||||
->where('route_or_url','root')
|
||||
->orderBy('position')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,21 @@ class CountryCode extends Model
|
||||
{
|
||||
return $this->where('status', $status)->get();
|
||||
}
|
||||
|
||||
protected function countryHash()
|
||||
{
|
||||
$codes = $this->select('country_name', 'country_code')->get();
|
||||
return $codes->mapWithKeys(function ($item) {
|
||||
return [$item['country_name'] => $item['country_code']];
|
||||
});
|
||||
}
|
||||
|
||||
protected function code_countryHash()
|
||||
{
|
||||
$codes = $this->select('country_name', 'country_code')->get();
|
||||
return $codes->mapWithKeys(function ($item) {
|
||||
return [$item['country_code'] => $item['country_name']];
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
63
app/Models/CurrencyRates.php
Normal file
63
app/Models/CurrencyRates.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Models\CountryCode;
|
||||
|
||||
class CurrencyRates extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'v_currency';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'currency';
|
||||
/**
|
||||
* Indicates if the model's ID is auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
use HasFactory;
|
||||
|
||||
protected function actual(String $status)
|
||||
{
|
||||
return $this->get();
|
||||
}
|
||||
|
||||
protected function rates2EUR(String $status)
|
||||
{
|
||||
$rates = $this->actual("Y")->mapWithKeys(function ($item) {
|
||||
return [$item['currency'] => $item['rate']];
|
||||
});
|
||||
|
||||
return CountryCode::active("Y")->mapWithKeys(function ($item) use ($rates) {
|
||||
if ($item['currency_code'] == "EUR") return [$item["country_code"] => 1.0];
|
||||
return [$item["country_code"] => $rates[$item["currency_code"]]];
|
||||
});
|
||||
}
|
||||
|
||||
protected function currencyCode() {
|
||||
return CountryCode::active("Y")->mapWithKeys(function ($item) {
|
||||
return [$item['currency_code'] => $item['country_code']];
|
||||
});
|
||||
}
|
||||
|
||||
protected function countryCurrency() {
|
||||
return CountryCode::active("Y")->mapWithKeys(function ($item) {
|
||||
return [$item["country_code"] => $item["currency_code"]];
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
46
app/Models/IkeaProducts.php
Normal file
46
app/Models/IkeaProducts.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class IkeaProducts extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 't_ikea_products';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = null;
|
||||
/**
|
||||
* Indicates if the model's ID is auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
protected function search($item,$country = '')
|
||||
{
|
||||
if (strlen($item) >= 2 && strlen($item) < 5) {
|
||||
$result = $this->where('name', 'LIKE', $item . '%');
|
||||
if ($country != '') $result = $result->where('country',$country);
|
||||
return $result->get();
|
||||
} else if (strlen($item >= 5)) {
|
||||
$result = $this->where(function ($query) use ($item) { $query->where('typeName', 'LIKE', '%' . $item . '%')->orWhere('name', 'LIKE', '%' . $item . '%'); } );
|
||||
if ($country != '') $result = $result->where('country',$country);
|
||||
|
||||
return $result->get();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected function multisearch($codes, $countries) {
|
||||
//$countries = $
|
||||
// return $this->where('code',$codes)->where('country',$countries);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.7",
|
||||
"deployer/deployer": "^7.3",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"laravel/sail": "^1.0.1",
|
||||
"mockery/mockery": "^1.4.4",
|
||||
|
||||
45
composer.lock
generated
45
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ad6ab448ac9b62b01922490669b4c2b2",
|
||||
"content-hash": "86cdd8c61f5c7ee9dee51ebeae179259",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@@ -8787,6 +8787,49 @@
|
||||
],
|
||||
"time": "2023-08-25T18:43:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "deployer/deployer",
|
||||
"version": "v7.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/deployphp/deployer.git",
|
||||
"reference": "3535bdb2f6360662bd95f6e26fce31dbc269af64"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/deployphp/deployer/zipball/3535bdb2f6360662bd95f6e26fce31dbc269af64",
|
||||
"reference": "3535bdb2f6360662bd95f6e26fce31dbc269af64",
|
||||
"shasum": ""
|
||||
},
|
||||
"bin": [
|
||||
"dep"
|
||||
],
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anton Medvedev",
|
||||
"email": "anton@medv.io"
|
||||
}
|
||||
],
|
||||
"description": "Deployment Tool",
|
||||
"homepage": "https://deployer.org",
|
||||
"support": {
|
||||
"docs": "https://deployer.org/docs",
|
||||
"issues": "https://github.com/deployphp/deployer/issues",
|
||||
"source": "https://github.com/deployphp/deployer"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/antonmedv",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-07T10:27:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "2.0.0",
|
||||
|
||||
44
database/seeders/UserMenuSeeder.php
Normal file
44
database/seeders/UserMenuSeeder.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Menu;
|
||||
use App\Models\Permission;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class UserMenuSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$ikea = Menu::create([
|
||||
'name' => 'Ikea',
|
||||
'icon' => "house-chimney",
|
||||
'route_or_url' => 'root',
|
||||
'position' => 1,
|
||||
'deleteable' => false,
|
||||
]);
|
||||
|
||||
$about = $ikea->childs()->create([
|
||||
'name' => 'About',
|
||||
'route_or_url' => 'about',
|
||||
'icon' => 'circle-info',
|
||||
'position' => 1,
|
||||
'deleteable' => false,
|
||||
]);
|
||||
|
||||
$exchange = $ikea->childs()->create([
|
||||
'name' => 'Exchange',
|
||||
'route_or_url' => 'exchange',
|
||||
'icon' => 'circle-info',
|
||||
'position' => 2,
|
||||
'deleteable' => false,
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
19
deploy.yaml
Normal file
19
deploy.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
import:
|
||||
- recipe/laravel.php
|
||||
|
||||
config:
|
||||
repository: 'https://git.bh.ttx.sk/jaro/ikea/'
|
||||
|
||||
hosts:
|
||||
web01.ttx.sk:
|
||||
remote_user: git
|
||||
deploy_path: '/var/www/html/ikea'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
- cd: "/var/www/html/ikea/current"
|
||||
- run: "yarn install"
|
||||
- run: "yarn build"
|
||||
|
||||
after:
|
||||
deploy:failed: deploy:unlock
|
||||
15
lang/id.json
15
lang/id.json
@@ -96,5 +96,18 @@
|
||||
"referenceerror: ccount is not defined": "ReferenceError: ccount is not defined",
|
||||
"referenceerror: currency_code is not defined": "ReferenceError: currency_code is not defined",
|
||||
"referenceerror: assignment to undeclared variable acntry": "ReferenceError: assignment to undeclared variable aCntry",
|
||||
"referenceerror: _code is not defined": "ReferenceError: _code is not defined"
|
||||
"referenceerror: _code is not defined": "ReferenceError: _code is not defined",
|
||||
"referenceerror: acntry is not defined": "ReferenceError: aCntry is not defined",
|
||||
"error: request failed with status code 500": "Error: Request failed with status code 500",
|
||||
"error: ziggy error: 'item' parameter is required for route 'products.search'.": "Error: Ziggy error: 'item' parameter is required for route 'products.search'.",
|
||||
"firefox 122": "Firefox 122",
|
||||
"ikea": "Ikea",
|
||||
"about": "About",
|
||||
"exachange": "Exachange",
|
||||
"exchange": "Exchange",
|
||||
"referenceerror: rates is not defined": "ReferenceError: rates is not defined",
|
||||
"referenceerror: currency is not defined": "ReferenceError: currency is not defined",
|
||||
"typeerror: can't access property \"unshift\", currency.velue is undefined": "TypeError: can't access property \"unshift\", currency.velue is undefined",
|
||||
"item must be selected": "Item must be selected",
|
||||
"typeerror: can't access property \"code\", form.country.value is undefined": "TypeError: can't access property \"code\", form.country.value is undefined"
|
||||
}
|
||||
37
resources/js/Components/SearchInput.vue
Normal file
37
resources/js/Components/SearchInput.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
defineProps({
|
||||
modelValue: String,
|
||||
});
|
||||
|
||||
defineEmits(['update:modelValue']);
|
||||
|
||||
const input = ref(null);
|
||||
|
||||
// onMounted(() => {
|
||||
// if (input.value.hasAttribute('autofocus')) {
|
||||
// input.value.focus();
|
||||
// }
|
||||
// });
|
||||
|
||||
defineExpose({ focus: () => input.value.focus() });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center max-w-md mx-auto bg-white rounded-md">
|
||||
<div class="w-full">
|
||||
<input type="search" class="border-0 w-full px-4 py-1 text-gray-800 rounded-full focus:outline-none focus:ring-0"
|
||||
placeholder="search" x-model="search">
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="flex items-center bg-blue-500 justify-center w-12 h-12 text-white rounded-r-md">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
60
resources/js/Layouts/GuestLayout.vue
Normal file
60
resources/js/Layouts/GuestLayout.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<script setup>
|
||||
import Swal from 'sweetalert2';
|
||||
import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick, computed } from 'vue';
|
||||
import { FwbDropdown, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
||||
import LogoIkea from '@/assets/Ikea_logo.svg';
|
||||
import {
|
||||
FwbSelect,
|
||||
FwbNavbar,
|
||||
FwbNavbarCollapse,
|
||||
FwbNavbarLink,
|
||||
FwbNavbarLogo,
|
||||
} from 'flowbite-vue';
|
||||
|
||||
const menu = ref([])
|
||||
const fetch_menu = async () => {
|
||||
try {
|
||||
const response = await axios.get(route('menu.user'))
|
||||
menu.value = response.data;
|
||||
} catch (e) {
|
||||
const response = await Swal.fire({
|
||||
title: __('are you want to try again') + '?',
|
||||
text: __(`${e}`),
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
showCloseButton: true,
|
||||
})
|
||||
|
||||
response.isConfirmed && fetch()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(fetch_menu);
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<fwb-navbar>
|
||||
<template #logo>
|
||||
<fwb-navbar-logo alt="IKEA Price Craweler" :image-url="LogoIkea" :link="route('root')">
|
||||
IKEA Price Crawler
|
||||
</fwb-navbar-logo>
|
||||
</template>
|
||||
|
||||
<template #default="{ isShowMenu }">
|
||||
<fwb-navbar-collapse :is-show-menu="isShowMenu" v-if="menu.length > 0">
|
||||
<fwb-navbar-link :link="route(menu[0].route_or_url)">
|
||||
Home
|
||||
</fwb-navbar-link>
|
||||
<template v-for="item in menu[0].childs" v-if="menu.length > 0">
|
||||
<fwb-navbar-link :link="route(item.route_or_url)">
|
||||
{{ item.name }}
|
||||
</fwb-navbar-link>
|
||||
</template>
|
||||
</fwb-navbar-collapse>
|
||||
</template>
|
||||
</fwb-navbar>
|
||||
<div class="m-3">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
34
resources/js/Pages/IkeaAbout.vue
Normal file
34
resources/js/Pages/IkeaAbout.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<script setup>
|
||||
import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick, computed } from 'vue';
|
||||
import GuestLayout from '../Layouts/GuestLayout.vue';
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GuestLayout>
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
|
||||
<div class="bg-indigo-800 text-white font-bold rounded-lg border shadow-lg p-10">
|
||||
<h1>What is Ikea price comparison?</h1>
|
||||
<p>
|
||||
It is a community project of a group of enthusiasts from Slovakia.
|
||||
This service provides price comparison of Ikea products in European countries.
|
||||
Product prices are converted to EUR at the current rate and appear in resulting table.
|
||||
Information about the prices of Ikea products is obtained online.
|
||||
You can go to the appropriate product page by clicking on the country name.
|
||||
Thanks to this service, you can find out in which country a given Ikea product is the cheapest (you can sort
|
||||
them in the resulting table).
|
||||
</p>
|
||||
<br />
|
||||
Enjoy :)
|
||||
</div>
|
||||
</div>
|
||||
</GuestLayout>
|
||||
</template>
|
||||
<style>
|
||||
@import 'vue3-easy-data-table/dist/style.css';
|
||||
</style>
|
||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||
16
resources/js/Pages/IkeaExchange.vue
Normal file
16
resources/js/Pages/IkeaExchange.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick, computed } from 'vue';
|
||||
import GuestLayout from '../Layouts/GuestLayout.vue';
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GuestLayout>
|
||||
<div class="flex flex-wrap gap-2 justify-center align-middle ">
|
||||
<h1>Exchange</h1>
|
||||
</div>
|
||||
</GuestLayout>
|
||||
</template>
|
||||
@@ -1,28 +1,71 @@
|
||||
<script setup>
|
||||
import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick } from 'vue';
|
||||
import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick, computed } from 'vue';
|
||||
import Swal from 'sweetalert2';
|
||||
import LogoIkea from '@/assets/Ikea_logo.svg';
|
||||
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import { GChart } from 'vue-google-charts';
|
||||
import { FwbDropdown, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
||||
|
||||
import EasyTable from "vue3-easy-data-table";
|
||||
//import autocomplete from '@trevoreyre/autocomplete-vue';
|
||||
import GuestLayout from '../Layouts/GuestLayout.vue';
|
||||
|
||||
|
||||
import {
|
||||
FwbNavbar,
|
||||
FwbNavbarCollapse,
|
||||
FwbNavbarLink,
|
||||
FwbNavbarLogo,
|
||||
} from 'flowbite-vue';
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import axios from 'axios';
|
||||
import IkeaLogo from './Ikea/IkeaLogo.vue';
|
||||
const type = 'GeoChart';
|
||||
|
||||
const props = defineProps({
|
||||
products: {
|
||||
type: Object,
|
||||
default: []
|
||||
},
|
||||
countryHash: {
|
||||
type: Object,
|
||||
default: []
|
||||
},
|
||||
menu: {
|
||||
type: Object,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
|
||||
console.log(props.countryHash);
|
||||
let tproducts = computed(() => {
|
||||
return props.products.map((prod) => {
|
||||
prod.salesPrice = parseFloat(prod.salesPrice);
|
||||
prod.country = props.countryHash[prod.country];
|
||||
return prod;
|
||||
})
|
||||
})
|
||||
|
||||
const type = 'GeoChart';
|
||||
const form = useForm({
|
||||
countries: '',
|
||||
country: '',
|
||||
codes: '',
|
||||
currency: 'EUR',
|
||||
});
|
||||
|
||||
const ccodes = ref([]);
|
||||
const ccountry = ref([]);
|
||||
const ccountry_filter = ref([['Country'],]);
|
||||
const ccountry_list = ref(['TEST']);
|
||||
const selected = ref(null);
|
||||
const article = ref('');
|
||||
const currency = ref([]);
|
||||
const hrates = ref([
|
||||
{ text: "Currency", value: "currency", sortable: true },
|
||||
{ text: "Country", value: "country_name", sortable: true },
|
||||
{ text: "Rate", value: "rate", sortable: true }
|
||||
]);
|
||||
// { "country": "AT", "code": "50161321", "url": "https://www.ikea.com/at/de/p/hol-aufbewahrungstisch-akazie-50161321/", "name": "HOL", "typeName": "Aufbewahrungstisch", "mainImageUrl": "https://www.ikea.com/at/de/images/products/hol-aufbewahrungstisch-akazie__0104310_pe251255_s5.jpg", "itemNoGlobal": "50161321", "salesPrice": "80.99", "tag": "FAMILY_PRICE", "last_mod": "2023-12-03 16:44:24" },
|
||||
const hproducts = ref([
|
||||
{ text: "Country", value: "country", sortable: true },
|
||||
{ text: "Name", value: "name", sortable: true },
|
||||
{ text: "Price", value: "salesPrice", sortable: true }
|
||||
]);
|
||||
|
||||
const rates = ref([]);
|
||||
const options_items = ref([]);
|
||||
const selected_item = ref(null);
|
||||
|
||||
const options = {
|
||||
region: 150,
|
||||
@@ -44,7 +87,9 @@ const gchartEvents = ref({
|
||||
}
|
||||
},);
|
||||
|
||||
|
||||
const sleep = (ms) => {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
const fetch = async () => {
|
||||
try {
|
||||
@@ -70,6 +115,73 @@ const fetch = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const fetch_rates = async () => {
|
||||
try {
|
||||
const response = await axios.get(route('rates.index'))
|
||||
rates.value = response.data;
|
||||
currency.value = rates.value.map((currency) => currency.currency);
|
||||
currency.value.unshift('EUR');
|
||||
console.log("RATE=", rates.value);
|
||||
} catch (e) {
|
||||
const response = await Swal.fire({
|
||||
title: __('are you want to try again') + '?',
|
||||
text: __(`${e}`),
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
showCloseButton: true,
|
||||
})
|
||||
|
||||
response.isConfirmed && fetch()
|
||||
}
|
||||
}
|
||||
|
||||
const fetch_ccodes = async () => {
|
||||
try {
|
||||
const response = await axios.get(route('ccountry.codes'))
|
||||
ccodes.value = response.data;
|
||||
ccodes.value = Object.entries(ccodes.value).map(([k, v]) => { if (v !== null) return { "country": k, "code": v } }).filter(n => n);
|
||||
console.log("ccodes=", ccodes.value);
|
||||
} catch (e) {
|
||||
const response = await Swal.fire({
|
||||
title: __('are you want to try again') + '?',
|
||||
text: __(`${e}`),
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
showCloseButton: true,
|
||||
})
|
||||
|
||||
response.isConfirmed && fetch()
|
||||
}
|
||||
}
|
||||
|
||||
const async_search = async (item) => {
|
||||
try {
|
||||
if (item.length >= 2) {
|
||||
|
||||
console.log('SEARCH', item, form.country.code, route('products.search', [item, form.country.code]));
|
||||
const response = await axios.get(route('products.search', [item, form.country.code]));
|
||||
|
||||
options_items.value = response.data.map((i) => { return { "item": i.name, "desc": i.typeName, "img": i.mainImageUrl, "code": i.code, "url": i.url } });
|
||||
console.log("VALUES=", options_items.value);
|
||||
}
|
||||
} catch (e) {
|
||||
const response = await Swal.fire({
|
||||
title: __('are you want to try again') + '?',
|
||||
text: __(`${e}`),
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
showCloseButton: true,
|
||||
})
|
||||
|
||||
response.isConfirmed && fetch()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function customLabel({ item, desc, code }) {
|
||||
//console.log(item);
|
||||
return `${item} - ${desc} - ${code}`;
|
||||
}
|
||||
const headers = ref([
|
||||
{ text: "Id", value: "id", sortable: true },
|
||||
{ text: "Country", value: "country", sortable: true },
|
||||
@@ -79,69 +191,101 @@ const items = ref([]);
|
||||
|
||||
function selectCountry(item, id) {
|
||||
let cCntry = [['Country'],];
|
||||
let aCntry = selected.value.map((country) => [country]);
|
||||
console.log(form.countries);
|
||||
let aCntry = form.countries.map((country) => [country]);
|
||||
|
||||
ccountry_filter.value = cCntry;
|
||||
ccountry_filter.value.push(...aCntry);
|
||||
}
|
||||
|
||||
onMounted(fetch);
|
||||
onMounted(fetch_rates);
|
||||
onMounted(fetch_ccodes);
|
||||
|
||||
const submit = () => {
|
||||
console.log('ITEM=', form);
|
||||
if (form.codes.length == 0) {
|
||||
Swal.fire({
|
||||
title: "Empty code",
|
||||
text: "You must enter product!",
|
||||
icon: "error"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
form.post(route('products.compare'));
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<fwb-navbar>
|
||||
<template #logo>
|
||||
<fwb-navbar-logo alt="IKEA Price Craweler" :image-url="LogoIkea" link="#">
|
||||
IKEA Price Crawler
|
||||
</fwb-navbar-logo>
|
||||
</template>
|
||||
<template #default="{ isShowMenu }">
|
||||
<fwb-navbar-collapse :is-show-menu="isShowMenu">
|
||||
<fwb-navbar-link is-active link="#">
|
||||
Home
|
||||
</fwb-navbar-link>
|
||||
<fwb-navbar-link link="#">
|
||||
Services
|
||||
</fwb-navbar-link>
|
||||
<fwb-navbar-link link="#">
|
||||
Pricing
|
||||
</fwb-navbar-link>
|
||||
<fwb-navbar-link link="#">
|
||||
Contact
|
||||
</fwb-navbar-link>
|
||||
</fwb-navbar-collapse>
|
||||
</template>
|
||||
</fwb-navbar>
|
||||
<div class="m-3">
|
||||
<GuestLayout>
|
||||
<div class="flex flex-wrap gap-2 justify-center align-middle ">
|
||||
<div class="justify-center rounded-md border-black border-8 max-h-[518px]">
|
||||
<GChart :events="gchartEvents" :type="type" :data="ccountry_filter" :options="options"
|
||||
:settings="chart_settings" />
|
||||
</div>
|
||||
<div class="mr-auto">
|
||||
<form @submit.prevent="submit">
|
||||
<div class="flex flex-col start-0">
|
||||
<span class="font-extrabold font-mono">Zadaj krajiny v ktorych chces vyhadavat</span>
|
||||
</div>
|
||||
<div>
|
||||
<multiselect :close-on-select="false" :multiple="true" v-model="selected" :options="ccountry_list"
|
||||
<multiselect :close-on-select="false" :multiple="true" v-model="form.countries" :options="ccountry_list"
|
||||
@select="selectCountry" @remove="selectCountry">
|
||||
</multiselect>
|
||||
</div>
|
||||
<div class="flex flex-col start-0">
|
||||
<span class="font-extrabold font-mono">Krajina produktu na vyhladanie</span>
|
||||
</div>
|
||||
<div>
|
||||
<multiselect :close-on-select="false" :multiple="false" v-model="form.country" :options="ccodes"
|
||||
label="country" track-by="code">
|
||||
</multiselect>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-extrabold font-mono">Zadaj polozku</span>
|
||||
</div>
|
||||
<div>
|
||||
<multiselect :multiple="false" :options="[]">
|
||||
|
||||
</multiselect>
|
||||
<multiselect v-model="form.codes" label="item" track-by="item" :custom-label="customLabel"
|
||||
:internal-search="false" placeholder="Find item" :searchable="true" :options="options_items"
|
||||
@search-change="async_search" />
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-extrabold font-mono">Prepocet do meny</span>
|
||||
</div>
|
||||
<div>
|
||||
<multiselect v-model="form.currency" :multiple="false" :allow-empty="false" placeholder="Currency"
|
||||
:searchable="true" :options="currency" />
|
||||
</div>
|
||||
<div class="text-end mt-2">
|
||||
<button type="submit"
|
||||
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||
:disabled="form.processing" :class="{ 'opacity-25': form.processing }">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-5">
|
||||
<EasyTable :rows-per-page=10 :headers="headers" :items="items" alternating></EasyTable>
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
<EasyTable :rows-per-page=10 :headers="headers" :items="items"></EasyTable>
|
||||
<EasyTable :rows-per-page=15 :headers="hrates" :items="rates" alternating></EasyTable>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex flex-col start-0">
|
||||
<span class="font-extrabold font-mono">Vysledky vyhladavania</span>
|
||||
</div>
|
||||
<div>
|
||||
<EasyTable :rows-per-page=15 :headers="hproducts" :items="tproducts" alternating>
|
||||
<template #item-name="{ name, url }">
|
||||
<a class="underline" target="_blank" :href="url">{{ name }}</a>
|
||||
</template>
|
||||
</EasyTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GuestLayout>
|
||||
</template>
|
||||
<style>
|
||||
@import 'vue3-easy-data-table/dist/style.css';
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
@inertiaHead
|
||||
</head>
|
||||
|
||||
<body class="font-sans antialiased gradient">
|
||||
<body class="font-sans antialiased bg-gray-100">
|
||||
@inertia
|
||||
</body>
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ use Illuminate\Support\Facades\Route;
|
||||
use Inertia\Inertia;
|
||||
use App\Http\Controllers\CountryCodeController;
|
||||
use App\Http\Controllers\CountryCompareController;
|
||||
use App\Http\Controllers\CurrencyRatesController;
|
||||
use App\Http\Controllers\IkeaProductsController;
|
||||
use App\Http\Controllers\ProductsCompareController;
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Web Routes
|
||||
@@ -18,10 +23,23 @@ use App\Http\Controllers\CountryCompareController;
|
||||
Route::get('/', function () {
|
||||
return Inertia::render('IkeaRoot');
|
||||
})->name('root');
|
||||
Route::get('/about/', function () {
|
||||
return Inertia::render('IkeaAbout');
|
||||
})->name('about');
|
||||
Route::get('/exchange/', function () {
|
||||
return Inertia::render('IkeaExchange');
|
||||
})->name('exchange');
|
||||
|
||||
Route::get('/menu/get', [App\Http\Controllers\Superuser\UserMenuController::class, 'get'])->name('menu.user');
|
||||
|
||||
Route::get('/ccountry/', [CountryCodeController::class, 'index'])->name('ccountry.index');
|
||||
Route::get('/ccountry/codes/', [CountryCodeController::class, 'codes'])->name('ccountry.codes');
|
||||
Route::get('/ccountry/active/', [CountryCodeController::class, 'active'])->name('ccountry.active');
|
||||
Route::get('/search/{id}',[CountryCompareController::class,'search'])->name('ccompare.search');
|
||||
Route::get('/rates/', [CurrencyRatesController::class, 'index'])->name('rates.index');
|
||||
Route::get('/products/{item}/{country?}', [IkeaProductsController::class, 'search'])->name('products.search');
|
||||
Route::post('/products/compare/', [ProductsCompareController::class, 'compare'])->name('products.compare');
|
||||
|
||||
Route::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified'])->group(function () {
|
||||
// Route::get('/', function () {
|
||||
// return Inertia::render('Dashboard');
|
||||
@@ -65,7 +83,7 @@ Route::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified']
|
||||
Route::get('/role/get', [App\Http\Controllers\Superuser\RoleController::class, 'get'])->name('role');
|
||||
Route::post('/role/paginate', [App\Http\Controllers\Superuser\RoleController::class, 'paginate'])->name('role.paginate');
|
||||
Route::post('/user/paginate', [App\Http\Controllers\Superuser\UserController::class, 'paginate'])->name('user.paginate');
|
||||
Route::post('/activity/login', [App\Http\Controllers\ActivityController::class, 'logins'])->name('activity.login');
|
||||
Route::post('/activity/login', [App\Http\Controllers\ActivityController::class, 'logins'])->name('activity.login.post');
|
||||
Route::get('/menu/get', [App\Http\Controllers\Superuser\MenuController::class, 'get'])->name('menu');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user