Compare commits

...

32 Commits

Author SHA1 Message Date
9f9420643e underline in product result
Some checks failed
deploy / deploy (push) Has been cancelled
2024-01-04 20:07:27 +01:00
a2caa6f847 url in results
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-04 20:05:30 +01:00
33219a4d88 label with code and fix bug with search null country
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 22:03:13 +01:00
9d98ad7a10 Yarn package
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 21:49:27 +01:00
2f407d9530 remove gradient
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 21:36:06 +01:00
cf8844471b Search in products with country
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 21:28:11 +01:00
fbcc3226fe search with country
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 20:44:19 +01:00
597f9c111f Error on search empty product
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 18:41:37 +01:00
a5c3da9436 search in typename if lengith > 2
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-03 18:17:04 +01:00
49c0c94ec9 caclulate rate currency result
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-02 22:13:27 +01:00
68418d1205 About fix
Some checks failed
deploy / deploy (push) Has been cancelled
2024-01-01 16:35:26 +01:00
f41e77a3a7 Search with 3 characters in products name and 5 charcters in descriptiom
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-01 13:35:21 +01:00
73de3a69b9 Basic Menu
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-01 11:14:01 +01:00
bb1e38d274 Seeder user menu, Guest Layout fix
Some checks are pending
deploy / deploy (push) Waiting to run
2024-01-01 10:53:19 +01:00
9bbd65eaaf Split Layout, menu define
Some checks are pending
deploy / deploy (push) Waiting to run
2023-12-31 22:08:22 +01:00
0a9205ea8b Tasks and Deployer updates
Some checks failed
deploy / deploy (push) Has been cancelled
2023-12-30 07:49:00 +01:00
22756f3f31 Fix post route:cache
Some checks are pending
deploy / deploy (push) Waiting to run
2023-12-29 18:24:09 +01:00
8139bcbad9 Deploy test 2
Some checks failed
deploy / deploy (push) Failing after 10m33s
2023-12-29 17:44:46 +01:00
399099a802 Deploy test
Some checks are pending
deploy / deploy (push) Waiting to run
2023-12-29 17:28:27 +01:00
45c2fe0485 Merge branch 'master' of https://git.bh.ttx.sk/jaro/ikea
Some checks failed
deploy / deploy (push) Waiting to run
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 2s
2023-12-29 17:15:28 +01:00
f58b69cc15 Test deploy 2023-12-29 17:15:23 +01:00
c7360e254a Update .gitea/workflows/build.yaml
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
2023-12-28 19:02:22 +01:00
604293aef4 Update .gitea/workflows/build.yaml
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
2023-12-28 18:59:26 +01:00
f1ec98e0d4 Update .gitea/workflows/build.yaml 2023-12-28 18:58:52 +01:00
8209ea594a Update .gitea/workflows/build.yaml
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 11s
2023-12-28 18:58:07 +01:00
2df03900ee Update .gitea/workflows/build.yaml 2023-12-28 18:56:14 +01:00
3d35977e57 Update .gitea/workflows/build.yaml 2023-12-28 18:51:30 +01:00
67967c7def w1
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 10s
2023-12-28 17:51:50 +01:00
e55e88fa62 fix name of country
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 10s
2023-12-26 16:03:10 +01:00
82c9971289 Fix search, remove, add countries 2023-12-25 21:45:08 +01:00
4375ac1fc8 Basic search 2023-12-25 17:23:45 +01:00
3cfa2e3513 Basic search
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2023-12-05 21:49:32 +01:00
22 changed files with 698 additions and 106 deletions

View File

@@ -1,18 +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 /var/www/html
- run: echo "🍏 This job's status is ${{ job.status }}."
- uses: actions/checkout@v2

View 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
View 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

View File

@@ -22,6 +22,10 @@ class CountryCodeController extends Controller
return CountryCode::active("Y"); return CountryCode::active("Y");
} }
public function codes()
{
return CountryCode::countryHash();
}
/** /**
* Store a newly created resource in storage. * Store a newly created resource in storage.
* *

View File

@@ -10,4 +10,5 @@ class CurrencyRatesController extends Controller
{ {
return CurrencyRates::all(); return CurrencyRates::all();
} }
} }

View 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);
}
}

View 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,
]);
}
}

View 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();
}
}

View File

@@ -7,30 +7,47 @@ use Illuminate\Database\Eloquent\Model;
class CountryCode extends Model class CountryCode extends Model
{ {
/** /**
* The table associated with the model. * The table associated with the model.
* *
* @var string * @var string
*/ */
protected $table = 'c_ikea_country_code'; protected $table = 'c_ikea_country_code';
/** /**
* The primary key associated with the table. * The primary key associated with the table.
* *
* @var string * @var string
*/ */
protected $primaryKey = 'currency_code'; protected $primaryKey = 'currency_code';
/** /**
* Indicates if the model's ID is auto-incrementing. * Indicates if the model's ID is auto-incrementing.
* *
* @var bool * @var bool
*/ */
public $incrementing = false; public $incrementing = false;
use HasFactory; use HasFactory;
protected function active(String $status)
{
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']];
});
}
protected function active(String $status)
{
return $this->where('status', $status)->get();
}
} }

View File

@@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use App\Models\CountryCode;
class CurrencyRates extends Model class CurrencyRates extends Model
{ {
@@ -34,4 +35,29 @@ class CurrencyRates extends Model
{ {
return $this->get(); 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"]];
});
}
} }

View 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);
}
}

View File

@@ -23,6 +23,7 @@
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.7", "barryvdh/laravel-debugbar": "^3.7",
"deployer/deployer": "^7.3",
"fakerphp/faker": "^1.9.1", "fakerphp/faker": "^1.9.1",
"laravel/sail": "^1.0.1", "laravel/sail": "^1.0.1",
"mockery/mockery": "^1.4.4", "mockery/mockery": "^1.4.4",

45
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ad6ab448ac9b62b01922490669b4c2b2", "content-hash": "86cdd8c61f5c7ee9dee51ebeae179259",
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@@ -8787,6 +8787,49 @@
], ],
"time": "2023-08-25T18:43:57+00:00" "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", "name": "doctrine/instantiator",
"version": "2.0.0", "version": "2.0.0",

View 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
View 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

View File

@@ -98,5 +98,16 @@
"referenceerror: assignment to undeclared variable acntry": "ReferenceError: assignment to undeclared variable aCntry", "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", "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: 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"
} }

View 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>

View 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>

View 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>

View File

@@ -1,36 +1,71 @@
<script setup> <script setup>
import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick } from 'vue'; import { getCurrentInstance, ref, onMounted, onUnmounted, nextTick, computed } from 'vue';
import Swal from 'sweetalert2'; import Swal from 'sweetalert2';
import LogoIkea from '@/assets/Ikea_logo.svg';
import Multiselect from 'vue-multiselect'; import Multiselect from 'vue-multiselect';
import { GChart } from 'vue-google-charts'; import { GChart } from 'vue-google-charts';
import { FwbDropdown, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
import EasyTable from "vue3-easy-data-table"; import EasyTable from "vue3-easy-data-table";
import SearchInput from '@/Components/SearchInput.vue'; import GuestLayout from '../Layouts/GuestLayout.vue';
//import autocomplete from '@trevoreyre/autocomplete-vue';
import { useForm } from '@inertiajs/inertia-vue3'
import {
FwbNavbar,
FwbNavbarCollapse,
FwbNavbarLink,
FwbNavbarLogo,
} from 'flowbite-vue';
import axios from 'axios'; import axios from 'axios';
import IkeaLogo from './Ikea/IkeaLogo.vue'; 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 = ref([]);
const ccountry_filter = ref([['Country'],]); const ccountry_filter = ref([['Country'],]);
const ccountry_list = ref(['TEST']); const ccountry_list = ref(['TEST']);
const selected = ref(null); const selected = ref(null);
const article = ref(''); const article = ref('');
const currency = ref([]);
const hrates = ref([ const hrates = ref([
{ text: "Currency", value: "currency", sortable: true}, { text: "Currency", value: "currency", sortable: true },
{ text: "Country", value: "country_name", sortable: true}, { text: "Country", value: "country_name", sortable: true },
{ text: "Rate", value: "rate", 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 rates = ref([]);
const options_items = ref([]);
const selected_item = ref(null);
const options = { const options = {
region: 150, region: 150,
@@ -52,7 +87,9 @@ const gchartEvents = ref({
} }
},); },);
const sleep = (ms) => {
return new Promise(resolve => setTimeout(resolve, ms))
}
const fetch = async () => { const fetch = async () => {
try { try {
@@ -82,6 +119,8 @@ const fetch_rates = async () => {
try { try {
const response = await axios.get(route('rates.index')) const response = await axios.get(route('rates.index'))
rates.value = response.data; rates.value = response.data;
currency.value = rates.value.map((currency) => currency.currency);
currency.value.unshift('EUR');
console.log("RATE=", rates.value); console.log("RATE=", rates.value);
} catch (e) { } catch (e) {
const response = await Swal.fire({ const response = await Swal.fire({
@@ -96,6 +135,53 @@ const fetch_rates = async () => {
} }
} }
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([ const headers = ref([
{ text: "Id", value: "id", sortable: true }, { text: "Id", value: "id", sortable: true },
{ text: "Country", value: "country", sortable: true }, { text: "Country", value: "country", sortable: true },
@@ -105,7 +191,8 @@ const items = ref([]);
function selectCountry(item, id) { function selectCountry(item, id) {
let cCntry = [['Country'],]; 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 = cCntry;
ccountry_filter.value.push(...aCntry); ccountry_filter.value.push(...aCntry);
@@ -113,62 +200,92 @@ function selectCountry(item, id) {
onMounted(fetch); onMounted(fetch);
onMounted(fetch_rates); 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> </script>
<template> <template>
<fwb-navbar> <GuestLayout>
<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">
<div class="flex flex-wrap gap-2 justify-center align-middle "> <div class="flex flex-wrap gap-2 justify-center align-middle ">
<div class="justify-center rounded-md border-black border-8 max-h-[518px]"> <div class="justify-center rounded-md border-black border-8 max-h-[518px]">
<GChart :events="gchartEvents" :type="type" :data="ccountry_filter" :options="options" <GChart :events="gchartEvents" :type="type" :data="ccountry_filter" :options="options"
:settings="chart_settings" /> :settings="chart_settings" />
</div> </div>
<div class="mr-auto"> <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="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 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=15 :headers="hrates" :items="rates" alternating></EasyTable>
</div>
</div>
<div>
<div class="flex flex-col start-0"> <div class="flex flex-col start-0">
<span class="font-extrabold font-mono">Zadaj krajiny v ktorych chces vyhadavat</span> <span class="font-extrabold font-mono">Vysledky vyhladavania</span>
</div> </div>
<div> <div>
<multiselect :close-on-select="false" :multiple="true" v-model="selected" :options="ccountry_list" <EasyTable :rows-per-page=15 :headers="hproducts" :items="tproducts" alternating>
@select="selectCountry" @remove="selectCountry"> <template #item-name="{ name, url }">
</multiselect> <a class="underline" target="_blank" :href="url">{{ name }}</a>
</div> </template>
<div> </EasyTable>
<span class="font-extrabold font-mono">Zadaj polozku</span>
</div>
<div>
<SearchInput v-model="article"></SearchInput>
</div>
<div class="mt-5">
<EasyTable :rows-per-page=10 :headers="headers" :items="items"></EasyTable>
</div>
<div class="mt-5">
<EasyTable :rows-per-page=15 :headers="hrates" :items="rates"></EasyTable>
</div> </div>
</div> </div>
</div> </div>
</div>
</GuestLayout>
</template> </template>
<style> <style>
@import 'vue3-easy-data-table/dist/style.css'; @import 'vue3-easy-data-table/dist/style.css';

View File

@@ -24,7 +24,7 @@
@inertiaHead @inertiaHead
</head> </head>
<body class="font-sans antialiased gradient"> <body class="font-sans antialiased bg-gray-100">
@inertia @inertia
</body> </body>

View File

@@ -5,6 +5,10 @@ use Inertia\Inertia;
use App\Http\Controllers\CountryCodeController; use App\Http\Controllers\CountryCodeController;
use App\Http\Controllers\CountryCompareController; use App\Http\Controllers\CountryCompareController;
use App\Http\Controllers\CurrencyRatesController; use App\Http\Controllers\CurrencyRatesController;
use App\Http\Controllers\IkeaProductsController;
use App\Http\Controllers\ProductsCompareController;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Web Routes | Web Routes
@@ -19,12 +23,22 @@ use App\Http\Controllers\CurrencyRatesController;
Route::get('/', function () { Route::get('/', function () {
return Inertia::render('IkeaRoot'); return Inertia::render('IkeaRoot');
})->name('root'); })->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/', [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('/ccountry/active/', [CountryCodeController::class, 'active'])->name('ccountry.active');
Route::get('/search/{id}',[CountryCompareController::class,'search'])->name('ccompare.search'); Route::get('/search/{id}',[CountryCompareController::class,'search'])->name('ccompare.search');
Route::get('/rates/', [CurrencyRatesController::class, 'index'])->name('rates.index'); 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::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified'])->group(function () {
// Route::get('/', function () { // Route::get('/', function () {
@@ -69,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::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('/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('/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'); Route::get('/menu/get', [App\Http\Controllers\Superuser\MenuController::class, 'get'])->name('menu');
}); });
}); });