Compare commits

...

45 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
d3801506da Fix
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2023-12-04 20:37:31 +01:00
32d35aa4c7 TEST2 2023-12-04 20:30:25 +01:00
148a010f4d Rates, Build
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 12s
2023-12-04 20:04:46 +01:00
aff90ceb86 Test chcekout
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 10s
2023-12-01 21:17:23 +01:00
11be2f2f03 7
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
2023-12-01 21:07:54 +01:00
d4e8b7db60 TEST6
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2023-12-01 21:01:04 +01:00
01e67e5cb5 TEST5
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
2023-12-01 20:59:38 +01:00
d3bae105da TEST5
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
2023-12-01 20:54:38 +01:00
5cc07b7371 TEST4
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
2023-12-01 20:48:56 +01:00
4323698a94 TEST3
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
2023-12-01 20:46:19 +01:00
665159612c Test2
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
2023-12-01 20:33:43 +01:00
8875266134 Merge branch 'master' of https://git.bh.ttx.sk/jaro/ikea
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2023-12-01 20:29:33 +01:00
97096c3e31 Small fixes 2023-11-29 20:50:06 +01:00
25 changed files with 816 additions and 102 deletions

View File

@@ -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 }}."

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

2
TEST
View File

@@ -1,2 +1,2 @@
TEST2
333
3333

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");
}
public function codes()
{
return CountryCode::countryHash();
}
/**
* Store a newly created resource in storage.
*

View File

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

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

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
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'c_ikea_country_code';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'c_ikea_country_code';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'currency_code';
/**
* Indicates if the model's ID is auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'currency_code';
/**
* Indicates if the model's ID is auto-incrementing.
*
* @var bool
*/
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

@@ -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"]];
});
}
}

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": {
"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
View File

@@ -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",

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

@@ -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"
}

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

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,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">
<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"
@select="selectCountry" @remove="selectCountry">
</multiselect>
</div>
<div>
<span class="font-extrabold font-mono">Zadaj polozku</span>
</div>
<div>
<multiselect :multiple="false" :options="[]">
</multiselect>
<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=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>
</GuestLayout>
</template>
<style>
@import 'vue3-easy-data-table/dist/style.css';

View File

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

View File

@@ -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');
});
});