mirror of
https://github.com/anna-sara/lan_kiosk
synced 2026-03-16 19:55:41 +01:00
Feature: Create groups
This commit is contained in:
parent
0ee99592b5
commit
8770925309
20 changed files with 1019 additions and 82 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Customer;
|
use App\Models\Customer;
|
||||||
|
use App\Models\CustomerGroup;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\Purchase;
|
use App\Models\Purchase;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
|
|
@ -14,7 +15,8 @@ class CustomerController extends Controller
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$customers = Customer::orderBy('name', 'asc')->get();
|
$customers = Customer::where('is_in_group', 0)->orderBy('name', 'asc')->get();
|
||||||
|
|
||||||
return Inertia::render('Dashboard', ['customers' => $customers]);
|
return Inertia::render('Dashboard', ['customers' => $customers]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,16 +54,22 @@ class CustomerController extends Controller
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
$customer = Customer::with('purchases')->with('deposits')->findOrFail($id);
|
$customer = Customer::with('purchases')->with('deposits')->findOrFail($id);
|
||||||
|
$groupmembers = Customer::where('is_in_group', 1)->where('customer_group_id', $customer->customer_group_id)->get();
|
||||||
|
|
||||||
return Inertia::render('Customer', ['customer' => $customer]);
|
|
||||||
|
return Inertia::render('Customer', ['customer' => $customer, 'groupmembers' => $groupmembers]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for editing the specified resource.
|
* Show the form for editing the specified resource.
|
||||||
*/
|
*/
|
||||||
public function edit(Customers $customers)
|
public function edit($id)
|
||||||
{
|
{
|
||||||
//
|
$customer = Customer::findOrFail($id);
|
||||||
|
|
||||||
|
$customer->customer_group_id = null;
|
||||||
|
$customer->is_in_group = 0;
|
||||||
|
$customer->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -112,4 +120,5 @@ class CustomerController extends Controller
|
||||||
'success' => true, 'message' => 'Customer deleted successfully'
|
'success' => true, 'message' => 'Customer deleted successfully'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
142
app/Http/Controllers/CustomerGroupController.php
Normal file
142
app/Http/Controllers/CustomerGroupController.php
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\CustomerGroup;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use App\Models\Deposit;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Inertia\Inertia;
|
||||||
|
|
||||||
|
class CustomerGroupController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$groups = CustomerGroup::with('customers')->get();
|
||||||
|
$customers = Customer::whereNull('customer_group_id')->where('is_in_group', false)->orderBy('name', 'asc')->get();
|
||||||
|
|
||||||
|
return Inertia::render('CustomerGroups', ['groups' => $groups, 'customers' => $customers]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'group_name' => 'required',
|
||||||
|
'customers' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$customers = $request->customers;
|
||||||
|
|
||||||
|
$guardian_name = Customer::where('id', (int) $customers[0])->pluck('guardian_name');
|
||||||
|
|
||||||
|
$customerGroup = CustomerGroup::create([
|
||||||
|
'name' => $request->group_name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$groupCustomer = Customer::create([
|
||||||
|
'name' => $request->group_name,
|
||||||
|
'guardian_name' => $guardian_name[0],
|
||||||
|
'is_in_group' => false,
|
||||||
|
'customer_group_id' => $customerGroup->id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$groupAmount= 0;
|
||||||
|
|
||||||
|
foreach ($customers as $customerItem) {
|
||||||
|
$customer = Customer::findOrFail($customerItem);
|
||||||
|
$customer->customer_group_id = $customerGroup->id;
|
||||||
|
$customer->is_in_group = 1;
|
||||||
|
$groupAmount += $customer->deposit;
|
||||||
|
$customer->deposit = 0;
|
||||||
|
$customer->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Deposit::create([
|
||||||
|
'customer_id' => $groupCustomer->id,
|
||||||
|
'amount' => $groupAmount,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$groupCustomer->amount_left = $groupAmount;
|
||||||
|
$groupCustomer->deposit = $groupAmount;
|
||||||
|
$groupCustomer->save();
|
||||||
|
|
||||||
|
return redirect('customer-groups/');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(CustomerGroup $customerGroup)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(CustomerGroup $customerGroup)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update($id, Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'customers' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$customers = $request->customers;
|
||||||
|
$groupCustomer = Customer::where('customer_group_id', $id)->where('is_in_group', 0)->first();
|
||||||
|
|
||||||
|
foreach ($customers as $customerItem) {
|
||||||
|
$customer = Customer::findOrFail($customerItem);
|
||||||
|
$groupCustomer->deposit += $customer->deposit;
|
||||||
|
$groupCustomer->amount_left += $customer->deposit;
|
||||||
|
$groupCustomer->save();
|
||||||
|
$customer->customer_group_id = $id;
|
||||||
|
$customer->is_in_group = 1;
|
||||||
|
$customer->deposit = 0;
|
||||||
|
$customer->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true, 'message' => 'Customer group was updated'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
$group = CustomerGroup::findOrFail( $id );
|
||||||
|
$customerGroup = Customer::where('customer_group_id', $group->id);
|
||||||
|
$customerGroup->delete();
|
||||||
|
$group->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true, 'message' => 'Customer group deleted successfully'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,12 +41,37 @@ class DepositController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$customer = Customer::findOrFail($request->customer_id);
|
$customer = Customer::findOrFail($request->customer_id);
|
||||||
|
|
||||||
|
if ($customer->is_in_group) {
|
||||||
|
$groupCustomer = Customer::where('customer_group_id', $customer->customer_group_id)->where('is_in_group', 0)->first();
|
||||||
|
$groupCustomer->deposit += $customer->deposit;
|
||||||
|
$groupCustomer->amount_left += $request->deposit;
|
||||||
|
$groupCustomer->save();
|
||||||
|
$customer->deposit = 0;
|
||||||
|
$customer->save();
|
||||||
|
|
||||||
|
if ($request->manual_deposit === 1) {
|
||||||
|
return redirect('customer/' . $request->customer_id);
|
||||||
|
}
|
||||||
|
return response()->json([
|
||||||
|
'success' => true, 'message' => 'Deposit added successfully'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
$customer->deposit = $customer->deposit + $request->deposit;
|
$customer->deposit = $customer->deposit + $request->deposit;
|
||||||
$customer->amount_left = $customer->amount_left + $request->deposit;
|
$customer->amount_left = $customer->amount_left + $request->deposit;
|
||||||
$customer->save();
|
$customer->save();
|
||||||
|
|
||||||
|
if ($request->manual_deposit === 1) {
|
||||||
return redirect('customer/' . $request->customer_id);
|
return redirect('customer/' . $request->customer_id);
|
||||||
}
|
}
|
||||||
|
return response()->json([
|
||||||
|
'success' => true, 'message' => 'Deposit added successfully'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
|
|
|
||||||
27
app/Http/Middleware/ApiToken.php
Normal file
27
app/Http/Middleware/ApiToken.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class ApiToken
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if ($request->header('X-API-KEY') === config('app.apikey_deposit')) {
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return response()->json(['code' => 401, 'message' => 'Unauthorized']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,13 +14,16 @@ class Customer extends Model
|
||||||
* @var array<int, string>
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'lan_id',
|
||||||
'name',
|
'name',
|
||||||
'guardian_name',
|
'guardian_name',
|
||||||
'amount left',
|
'amount left',
|
||||||
'amount used',
|
'amount used',
|
||||||
'deposit',
|
'deposit',
|
||||||
'give_leftover',
|
'give_leftover',
|
||||||
'comment'
|
'comment',
|
||||||
|
'customer_group_id',
|
||||||
|
'is_in_group'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
26
app/Models/CustomerGroup.php
Normal file
26
app/Models/CustomerGroup.php
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use App\Models\Customer;
|
||||||
|
|
||||||
|
class CustomerGroup extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the customers for the group.
|
||||||
|
*/
|
||||||
|
public function customers()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Customer::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
app/Models/Tableversion.php
Normal file
13
app/Models/Tableversion.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Tableversion extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'table',
|
||||||
|
'version'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -123,4 +123,9 @@ return [
|
||||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'apikey_deposit' => env('API_KEY_DEPOSIT'),
|
||||||
|
'apilan_key' => env('API_LAN_KEY'),
|
||||||
|
'apilan_url' => env('API_LAN_URL'),
|
||||||
|
'apilan_clientcert_path' => env('API_LAN_CLIENTCERT_PATH')
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('customers', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_in_group')->default(false);
|
||||||
|
$table->integer('customer_group_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('customers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_in_group');
|
||||||
|
$table->dropColumn('customer_group_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('customer_groups', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('customer_groups');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('customers', function (Blueprint $table) {
|
||||||
|
$table->integer('lan_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('customers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('lan_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('tableversions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('table')->nullable();
|
||||||
|
$table->integer('version')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('tableversions');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -91,6 +91,10 @@ details {
|
||||||
right: 1em;
|
right: 1em;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
|
|
||||||
|
&.group {
|
||||||
|
top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
@ -113,3 +117,41 @@ details {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.customer-box:nth-child(even) {
|
||||||
|
background-color:rgba(0, 128, 187, 0.075)
|
||||||
|
}
|
||||||
|
|
||||||
|
.customers-list {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 5px;}
|
||||||
|
|
||||||
|
|
||||||
|
.add-customer-to-group-modal {
|
||||||
|
//display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
padding-top: 100px;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: rgb(0,0,0);
|
||||||
|
background-color: rgba(0,0,0,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-customer-to-group-modal-content {
|
||||||
|
background-color: #fefefe;
|
||||||
|
margin: auto;
|
||||||
|
padding: 40px;
|
||||||
|
width: 60%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.delete {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,15 +24,23 @@ export default function Authenticated({
|
||||||
<img className="navbar-logo" src="/img/logo.png" />
|
<img className="navbar-logo" src="/img/logo.png" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{/*
|
|
||||||
<div className="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
<div className="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
<NavLink
|
<NavLink
|
||||||
href={route('dashboard')}
|
href="/dashboard"
|
||||||
active={route().current('dashboard')}
|
active={route().current('dashboard')}
|
||||||
>
|
>
|
||||||
Dashboard
|
Deltagare
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>*/}
|
</div>
|
||||||
|
<div className="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
|
<NavLink
|
||||||
|
href="/customer-groups"
|
||||||
|
active={route().current('customer-groups')}
|
||||||
|
>
|
||||||
|
Grupper
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="hidden sm:ms-6 sm:flex sm:items-center">
|
<div className="hidden sm:ms-6 sm:flex sm:items-center">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import TextInput from '@/Components/TextInput';
|
import TextInput from '@/Components/TextInput';
|
||||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
||||||
import { Textarea } from '@headlessui/react';
|
|
||||||
import { Head, useForm } from '@inertiajs/react';
|
import { Head, useForm } from '@inertiajs/react';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { FormEventHandler } from 'react';
|
import { FormEventHandler } from 'react';
|
||||||
|
|
@ -8,6 +7,7 @@ import { FormEventHandler } from 'react';
|
||||||
interface CustomerProps {
|
interface CustomerProps {
|
||||||
customer:{
|
customer:{
|
||||||
id: number
|
id: number
|
||||||
|
lan_id: number,
|
||||||
name: string
|
name: string
|
||||||
deposit: number
|
deposit: number
|
||||||
amount_left: number
|
amount_left: number
|
||||||
|
|
@ -25,16 +25,31 @@ interface CustomerProps {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Customer({customer}: CustomerProps) {
|
interface GroupmembersProps {
|
||||||
|
groupmembers:[{
|
||||||
|
id: number
|
||||||
|
lan_id: number,
|
||||||
|
name: string
|
||||||
|
deposit: number
|
||||||
|
amount_left: number
|
||||||
|
give_leftover: number
|
||||||
|
guardian_name: string
|
||||||
|
comment: string;
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Customer({customer, groupmembers}: (CustomerProps & GroupmembersProps) ) {
|
||||||
|
|
||||||
const { data, setData, post, processing, errors, reset } = useForm({
|
const { data, setData, post, processing, errors, reset } = useForm({
|
||||||
amount: "",
|
amount: "",
|
||||||
customer_id: customer.id,
|
customer_id: customer.id,
|
||||||
deposit: "",
|
deposit: "",
|
||||||
id: customer.id,
|
id: customer.id,
|
||||||
comment: ""
|
comment: "",
|
||||||
|
manual_deposit: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const submit: FormEventHandler = (e) => {
|
const submit: FormEventHandler = (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
post(route('register_purchase'), {
|
post(route('register_purchase'), {
|
||||||
|
|
@ -47,10 +62,11 @@ export default function Customer({customer}: CustomerProps) {
|
||||||
const submitDeposit: FormEventHandler = (e) => {
|
const submitDeposit: FormEventHandler = (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
post(route('register_deposit'), {
|
post(route('register_deposit'), {
|
||||||
|
headers: {'X-API-KEY': '123', 'Accept': 'application/json', 'Content-Type': 'application/json'},
|
||||||
onFinish: () => setData(
|
onFinish: () => setData(
|
||||||
'deposit', ''
|
'deposit', ''
|
||||||
),
|
),
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateComment: FormEventHandler = (e) => {
|
const updateComment: FormEventHandler = (e) => {
|
||||||
|
|
@ -73,13 +89,24 @@ export default function Customer({customer}: CustomerProps) {
|
||||||
|
|
||||||
<section className='section'>
|
<section className='section'>
|
||||||
<div className="container is-max-desktop">
|
<div className="container is-max-desktop">
|
||||||
<h1 className="title is-2">{customer.name}</h1>
|
<a href="/dashboard" className="button mb-5 is-small is-white">Tillbaka</a>
|
||||||
|
<h1 className="title is-2">{customer.lan_id ? customer.lan_id + "." : "Grupp"} {customer.name}</h1>
|
||||||
<div className='container is-centered'>
|
<div className='container is-centered'>
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<h2 className='title is-4'>Saldo: {customer.amount_left ? customer.amount_left : 0} kr</h2>
|
<h2 className='title is-4'>Saldo: {customer.amount_left ? customer.amount_left : 0} kr</h2>
|
||||||
<p>Inbetalad summa: {customer.deposit ? customer.deposit : 0} kr</p>
|
<p>Inbetalad summa: {customer.deposit ? customer.deposit : 0} kr</p>
|
||||||
<p>Vårnadshavare: {customer.guardian_name}</p>
|
<p>Vårnadshavare: {customer.guardian_name}</p>
|
||||||
<p>Ge ev överblivet saldo till vBytes: {customer.give_leftover ? "Ja" : "Nej"}</p>
|
<p>Ge ev överblivet saldo till vBytes: {customer.give_leftover ? "Ja" : "Nej"}</p>
|
||||||
|
{groupmembers.length > 0 &&
|
||||||
|
<>
|
||||||
|
<h2 className='title is-5 mt-5 mb-2'>Gruppmedlemmar</h2>
|
||||||
|
{groupmembers && groupmembers.map( member => {
|
||||||
|
console.log(member)
|
||||||
|
return <p>{member.lan_id}. {member.name} </p>
|
||||||
|
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="box">
|
<div className="box">
|
||||||
|
|
@ -144,7 +171,7 @@ export default function Customer({customer}: CustomerProps) {
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
{groupmembers.length < 1 &&
|
||||||
<details className="box">
|
<details className="box">
|
||||||
<summary className='title is-4 my-3'>
|
<summary className='title is-4 my-3'>
|
||||||
<span>Inbetalning Swish/kontant</span>
|
<span>Inbetalning Swish/kontant</span>
|
||||||
|
|
@ -164,7 +191,7 @@ export default function Customer({customer}: CustomerProps) {
|
||||||
name="deposit"
|
name="deposit"
|
||||||
value={data.deposit}
|
value={data.deposit}
|
||||||
placeholder="Summa"
|
placeholder="Summa"
|
||||||
onChange={(e) => setData('deposit', e.target.value)}
|
onChange={(e) => [setData('deposit', e.target.value), setData('manual_deposit', 1)]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -181,7 +208,7 @@ export default function Customer({customer}: CustomerProps) {
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
<details className="box">
|
<details className="box">
|
||||||
|
|
|
||||||
384
resources/js/Pages/CustomerGroups.tsx
Normal file
384
resources/js/Pages/CustomerGroups.tsx
Normal file
|
|
@ -0,0 +1,384 @@
|
||||||
|
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
||||||
|
import TextInput from '@/Components/TextInput';
|
||||||
|
import { Head, useForm } from '@inertiajs/react';
|
||||||
|
import { FormEventHandler, SetStateAction, useState } from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
import Customer from './Customer';
|
||||||
|
|
||||||
|
|
||||||
|
interface CustomerProps {
|
||||||
|
customers: [{
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
customer_group_id: string,
|
||||||
|
is_in_group: boolean
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
type Customer = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
customer_group_id: string,
|
||||||
|
is_in_group: boolean
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
interface CustomerGroupProps {
|
||||||
|
groups: [{
|
||||||
|
name: string,
|
||||||
|
id: number,
|
||||||
|
customers: [{
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
customer_group_id: string,
|
||||||
|
is_in_group: boolean
|
||||||
|
}],
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
type CustomerGroup = {
|
||||||
|
name: string,
|
||||||
|
id: number,
|
||||||
|
customers: [{
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
customer_group_id: string,
|
||||||
|
is_in_group: boolean
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
type FormInputs = {
|
||||||
|
id: number | null;
|
||||||
|
customers: Customer[],
|
||||||
|
group_name: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
interface CurrentGroup {
|
||||||
|
id?: number | null ;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CustomerGroups({groups, customers} :( CustomerGroupProps & CustomerProps) ) {
|
||||||
|
const [addCustomerToGroupModal, setAddCustomerToGroupModal] = useState(false);
|
||||||
|
const [currentGroup, setCurrentGroup] = useState<CurrentGroup>({id: null, name: ""});
|
||||||
|
const [searchItemGroup, setSearchItemGroup] = useState('');
|
||||||
|
const [searchItemCustomers, setSearchItemCustomers] = useState('')
|
||||||
|
const [searchItemCustomersAddToGroup, setSearchItemCustomersAddToGroup] = useState('')
|
||||||
|
const [uniqueGroupNameError, setUniqueGroupNameError,] = useState(false)
|
||||||
|
const [activeTabLetter, setActiveTabLetter] = useState('')
|
||||||
|
const [activeTab, setActiveTab] = useState('groups')
|
||||||
|
const [filteredCustomers, setFilteredCustomers] = useState<Customer[]>(customers)
|
||||||
|
const [filteredCustomersAddToGroup, setFilteredCustomersAddToGroup] = useState<Customer[]>(customers)
|
||||||
|
const [filteredGroups, setFilteredGroups] = useState<CustomerGroup[]>(groups)
|
||||||
|
const [checkboxes, setCheckboxes] = useState<any[]>([]);
|
||||||
|
const [checkboxesAddToGroup, setCheckboxesAddToGroup] = useState<any[]>([]);
|
||||||
|
const letterArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Å","Ä","Ö"];
|
||||||
|
|
||||||
|
const { data, setData, post, processing, errors, reset } = useForm<FormInputs>({
|
||||||
|
id: null,
|
||||||
|
group_name: "",
|
||||||
|
customers: []
|
||||||
|
});
|
||||||
|
|
||||||
|
//Group
|
||||||
|
const handleInputChangeCreateGroup = (e: any) => {
|
||||||
|
const searchTerm = e.target.value;
|
||||||
|
setSearchItemCustomers(searchTerm)
|
||||||
|
|
||||||
|
const filteredItems = customers.filter((customer) =>
|
||||||
|
customer.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilteredCustomers(filteredItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitGroup: FormEventHandler = (e : any) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let submit = true;
|
||||||
|
groups.map( group => {
|
||||||
|
if (data.group_name.toLowerCase() === group.name.toLowerCase()) {
|
||||||
|
setUniqueGroupNameError(true);
|
||||||
|
submit = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (submit) {
|
||||||
|
post(route('register_customer_group'), {
|
||||||
|
onFinish: () => [setData(
|
||||||
|
'group_name', '',
|
||||||
|
|
||||||
|
), setCheckboxes([]),
|
||||||
|
window.location.href = "/customer-groups"],
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleInputChangeGroup = (e: any) => {
|
||||||
|
const searchTerm = e.target.value;
|
||||||
|
setSearchItemGroup(searchTerm)
|
||||||
|
|
||||||
|
const filteredItems = groups.filter((customer) =>
|
||||||
|
customer.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilteredGroups(filteredItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleInputClick = (searchTerm: string) => {
|
||||||
|
const filteredItems = groups.filter((customer) =>
|
||||||
|
customer.name.toLowerCase().startsWith(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilteredGroups(filteredItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCheckBoxChange = (e: any) => {
|
||||||
|
let index = e.target.dataset.id;
|
||||||
|
let prev = checkboxes;
|
||||||
|
let itemIndex = prev.indexOf(index);
|
||||||
|
if (itemIndex !== -1) {
|
||||||
|
prev.splice(itemIndex, 1);
|
||||||
|
} else {
|
||||||
|
prev.push(index);
|
||||||
|
}
|
||||||
|
setCheckboxes([...prev]);
|
||||||
|
setData('customers', checkboxes)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteCustomerGroup = (id: string | number | undefined) => {
|
||||||
|
axios.delete('/api/customer-group/' + id)
|
||||||
|
.then(response => {
|
||||||
|
window.location.href = "/customer-groups";
|
||||||
|
})
|
||||||
|
.catch(error => {console.log(error)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to group
|
||||||
|
const handleInputChangeAddToGroup = (e: any) => {
|
||||||
|
const searchTerm = e.target.value;
|
||||||
|
setSearchItemCustomersAddToGroup(searchTerm)
|
||||||
|
|
||||||
|
const filteredItems = customers.filter((customer) =>
|
||||||
|
customer.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilteredCustomersAddToGroup(filteredItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
const addToGroup = (id: number | null | undefined) => {
|
||||||
|
axios.post('/api/add-to-customer-group/' + id, {customers: data.customers})
|
||||||
|
.then(response => {
|
||||||
|
window.location.href = "/customer-groups";
|
||||||
|
})
|
||||||
|
.catch(error => {console.log(error)})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCheckBoxChangeAddToGroup = (e: any) => {
|
||||||
|
let index = e.target.dataset.id;
|
||||||
|
let prev = checkboxesAddToGroup;
|
||||||
|
let itemIndex = prev.indexOf(index);
|
||||||
|
if (itemIndex !== -1) {
|
||||||
|
prev.splice(itemIndex, 1);
|
||||||
|
} else {
|
||||||
|
prev.push(index);
|
||||||
|
}
|
||||||
|
setCheckboxesAddToGroup([...prev]);
|
||||||
|
setData('customers', checkboxesAddToGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteCustomerFromGroup = (id: string | number) => {
|
||||||
|
axios.put('/api/customer/' + id)
|
||||||
|
.then(response => {
|
||||||
|
window.location.href = "/customer-groups";
|
||||||
|
})
|
||||||
|
.catch(error => {console.log(error)})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthenticatedLayout>
|
||||||
|
<Head title="Dashboard" />
|
||||||
|
{ addCustomerToGroupModal &&
|
||||||
|
<div className='add-customer-to-group-modal'>
|
||||||
|
<div className='add-customer-to-group-modal-content'>
|
||||||
|
<button onClick={() => setAddCustomerToGroupModal(false)} className="delete is-large" aria-label="close"></button>
|
||||||
|
<form className='container is-centered'>
|
||||||
|
<h2 className="mt-4 title is-3" >Lägg till deltagare i grupp {currentGroup.name}</h2>
|
||||||
|
<div className='customers-list is-flex is-flex-direction-column gap-3 container is-centered my-4'>
|
||||||
|
{filteredCustomersAddToGroup && filteredCustomersAddToGroup
|
||||||
|
.map( customer => {
|
||||||
|
return <label className='checkbox'>
|
||||||
|
<input type="checkbox" className='mr-2' data-id={customer.id} onClick={handleCheckBoxChangeAddToGroup}/>
|
||||||
|
{customer.name}
|
||||||
|
</label>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className='input'
|
||||||
|
type="text"
|
||||||
|
value={searchItemCustomersAddToGroup}
|
||||||
|
onChange={handleInputChangeAddToGroup}
|
||||||
|
placeholder='Skriv för att söka deltagare/funktionär'
|
||||||
|
/>
|
||||||
|
<div className='is-flex mt-3'>
|
||||||
|
<span className='mr-2 has-text-weight-bold'>Valda deltagare/funktionärer: </span>
|
||||||
|
{filteredCustomersAddToGroup && filteredCustomersAddToGroup
|
||||||
|
.filter((filteredCustomer) => checkboxesAddToGroup.includes("" + filteredCustomer.id))
|
||||||
|
.map( customer => {
|
||||||
|
return <p key={customer.id} className='mr-2 tag'>
|
||||||
|
{customer.name}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<button onClick={() => addToGroup(currentGroup.id)} className="button mt-4 is-small is-white">Lägg till deltagare</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<section className='section'>
|
||||||
|
<div className="container is-max-desktop">
|
||||||
|
<a href="/dashboard" className="button mb-5 is-small is-white">Tillbaka</a>
|
||||||
|
<div className="tabs is-centered is-boxed">
|
||||||
|
<ul>
|
||||||
|
<li className={activeTab === "groups" ? "is-active" : ""}>
|
||||||
|
<a onClick={() => setActiveTab('groups') }>
|
||||||
|
<span>Grupper</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className={activeTab === "create-group" ? "is-active" : ""}>
|
||||||
|
<a onClick={() => setActiveTab('create-group') }>
|
||||||
|
<span>Skapa grupp</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{activeTab === "create-group" && <>
|
||||||
|
<h2 className="title is-2">Skapa grupp</h2>
|
||||||
|
<div className='create-group-container mb-7'>
|
||||||
|
<div>
|
||||||
|
<form onSubmit={submitGroup} className='container is-centered'>
|
||||||
|
<p className="mb-4">Namn på grupp:</p>
|
||||||
|
<TextInput
|
||||||
|
required
|
||||||
|
className="input"
|
||||||
|
type="text"
|
||||||
|
name="group_name"
|
||||||
|
value={data.group_name}
|
||||||
|
placeholder="Namn på grupp"
|
||||||
|
min={0}
|
||||||
|
//max={customer.group_name_left}
|
||||||
|
onChange={(e) => setData('group_name', e.target.value)}
|
||||||
|
/>
|
||||||
|
{uniqueGroupNameError && <p>Gruppnamn är inte unikt</p>}
|
||||||
|
|
||||||
|
<p className="mt-4" >Välj vilka som ska ingå i gruppen:</p>
|
||||||
|
|
||||||
|
<div className='customers-list is-flex is-flex-direction-column gap-3 container is-centered my-4'>
|
||||||
|
{filteredCustomers && filteredCustomers
|
||||||
|
.map( customer => {
|
||||||
|
return <label key={customer.id} className='checkbox'>
|
||||||
|
<input type="checkbox" className='mr-2' data-id={customer.id} onClick={handleCheckBoxChange}/>
|
||||||
|
{customer.name}
|
||||||
|
</label>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className='input'
|
||||||
|
type="text"
|
||||||
|
value={searchItemCustomers}
|
||||||
|
onChange={handleInputChangeCreateGroup}
|
||||||
|
placeholder='Skriv för att söka deltagare/funktionär'
|
||||||
|
/>
|
||||||
|
<div className='is-flex mt-3'>
|
||||||
|
<span className='mr-2 has-text-weight-bold'>Valda deltagare/funktionärer: </span>
|
||||||
|
{filteredCustomers && filteredCustomers
|
||||||
|
.filter((filteredCustomer) => checkboxes.includes("" + filteredCustomer.id))
|
||||||
|
.map( customer => {
|
||||||
|
return <p key={customer.id} className='mr-2 tag'>
|
||||||
|
{customer.name}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<button className="button mt-4 is-small is-white">Skapa grupp</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
{ activeTab === "groups" && <>
|
||||||
|
<h2 className="title is-2">Grupper</h2>
|
||||||
|
<input
|
||||||
|
className='input my-4'
|
||||||
|
type="text"
|
||||||
|
value={searchItemGroup}
|
||||||
|
onChange={handleInputChangeGroup}
|
||||||
|
placeholder='Skriv för att söka'
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<ul className='grid is-col-min-2 is-column-gap-1 mb-5'>
|
||||||
|
{ letterArray && letterArray.map( letter => {
|
||||||
|
return <li className={`${activeTabLetter == letter ? "is-active" : ""} cell button letter is-small is-white`} onClick={ () => [setActiveTabLetter(letter) ,handleInputClick(letter)]}>
|
||||||
|
{letter}
|
||||||
|
</li>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<li className='cell button is-small is-white' onClick={ () => [setActiveTabLetter(""), setFilteredGroups(groups), setSearchItemGroup("") ]}>
|
||||||
|
Rensa
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className='container is-centered'>
|
||||||
|
|
||||||
|
{filteredGroups && filteredGroups.map( group => {
|
||||||
|
return <details className="box">
|
||||||
|
<summary className='title is-4 my-3'>
|
||||||
|
<span>{group.name}</span>
|
||||||
|
<div className="summary-chevron-up">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" className="feather feather-chevron-down">
|
||||||
|
<polyline points="6 9 12 15 18 9"></polyline>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
{ group.customers.length < 2 &&
|
||||||
|
<button onClick={() => deleteCustomerGroup(group.id)} className="button is-danger is-outlined is-small">
|
||||||
|
<span>Ta bort grupp</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
<ul>
|
||||||
|
{ group.customers.length > 0 && group.customers.filter((customer) => customer.is_in_group).map( customer => {
|
||||||
|
return <div className='is-flex gap-4 border-b p-2 is-justify-content-space-between'>
|
||||||
|
<p className="is-size-5">{customer.name}</p>
|
||||||
|
<button onClick={() => deleteCustomerFromGroup(customer.id)} className="button is-danger is-outlined is-small">
|
||||||
|
<span>Ta bort från grupp</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
})}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<button className="button mt-4 is-small is-white" onClick={() => [setAddCustomerToGroupModal(true), setCurrentGroup({id: group.id, name: group.name})]}>Lägg till deltagare</button>
|
||||||
|
<div className="summary-chevron-down">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" className="feather feather-chevron-up">
|
||||||
|
<polyline points="18 15 12 9 6 15"></polyline>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</AuthenticatedLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
||||||
import { Head } from '@inertiajs/react';
|
import { Head, useForm } from '@inertiajs/react';
|
||||||
import { SetStateAction, useState } from 'react';
|
import {useState } from 'react';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faArrowRight } from '@fortawesome/free-solid-svg-icons'
|
import { faArrowRight } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
|
@ -9,21 +9,25 @@ interface CustomerProps {
|
||||||
customers: [{
|
customers: [{
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
group_id: string,
|
||||||
|
is_group: boolean
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Customer {
|
type Customer = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
group_id: string,
|
||||||
|
is_group: boolean
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default function Dashboard({ customers }: CustomerProps) {
|
||||||
export default function Dashboard({customers}: CustomerProps) {
|
|
||||||
const [searchItem, setSearchItem] = useState('')
|
const [searchItem, setSearchItem] = useState('')
|
||||||
const [activeTab, setActiveTab] = useState('')
|
const [activeTab, setActiveTab] = useState('')
|
||||||
const [filteredCustomers, setFilteredCustomers] = useState<Customer[]>(customers)
|
const [filteredCustomers, setFilteredCustomers] = useState<Customer[]>(customers)
|
||||||
const letterArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Å","Ä","Ö"];
|
const letterArray = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Å", "Ä", "Ö"];
|
||||||
|
|
||||||
const handleInputChange = (e: any) => {
|
const handleInputChange = (e: any) => {
|
||||||
const searchTerm = e.target.value;
|
const searchTerm = e.target.value;
|
||||||
|
|
@ -44,6 +48,7 @@ export default function Dashboard({customers}: CustomerProps) {
|
||||||
setFilteredCustomers(filteredItems);
|
setFilteredCustomers(filteredItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthenticatedLayout>
|
<AuthenticatedLayout>
|
||||||
<Head title="Dashboard" />
|
<Head title="Dashboard" />
|
||||||
|
|
@ -60,21 +65,21 @@ export default function Dashboard({customers}: CustomerProps) {
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<ul className='grid is-col-min-2 is-column-gap-1 mb-5'>
|
<ul className='grid is-col-min-2 is-column-gap-1 mb-5'>
|
||||||
{ letterArray && letterArray.map( letter => {
|
{letterArray && letterArray.map(letter => {
|
||||||
return <li className={`${activeTab == letter ? "is-active" : ""} cell button letter is-small is-white`} onClick={ () => [setActiveTab(letter) ,handleInputClick(letter)]}>
|
return <li className={`${activeTab == letter ? "is-active" : ""} cell button letter is-small is-white`} onClick={() => [setActiveTab(letter), handleInputClick(letter)]}>
|
||||||
{letter}
|
{letter}
|
||||||
</li>
|
</li>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<li className='cell button is-small is-white' onClick={ () => [setActiveTab(""), setFilteredCustomers(customers), setSearchItem("") ]}>
|
<li className='cell button is-small is-white' onClick={() => [setActiveTab(""), setFilteredCustomers(customers), setSearchItem("")]}>
|
||||||
Rensa
|
Rensa
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className='container is-centered'>
|
<div className='container is-centered'>
|
||||||
{filteredCustomers && filteredCustomers.map( customer => {
|
{filteredCustomers && filteredCustomers.map(customer => {
|
||||||
return <a key={customer.id} className="box is-flex is-justify-content-space-between" href={`/customer/` + customer.id}>
|
return <a key={customer.id} className="box customer-box is-flex is-justify-content-space-between" href={`/customer/` + customer.id}>
|
||||||
<p>{customer.name}</p>
|
<p>{customer.name}</p>
|
||||||
<span className="icon has-text-black">
|
<span className="icon has-text-black">
|
||||||
<FontAwesomeIcon icon={faArrowRight} />
|
<FontAwesomeIcon icon={faArrowRight} />
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,22 @@
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\CustomerController;
|
use App\Http\Controllers\CustomerController;
|
||||||
|
use App\Http\Controllers\CustomerGroupController;
|
||||||
use App\Http\Controllers\PurchaseController;
|
use App\Http\Controllers\PurchaseController;
|
||||||
use App\Http\Controllers\DepositController;
|
use App\Http\Controllers\DepositController;
|
||||||
|
use App\Http\Middleware\ApiToken;
|
||||||
|
|
||||||
Route::post('register_customer', [CustomerController::class, 'store'])->name('register_customer');
|
Route::post('register_customer', [CustomerController::class, 'store'])->name('register_customer');
|
||||||
|
|
||||||
Route::middleware('auth:sanctum')->group(function () {
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
Route::post('register_deposit', [DepositController::class, 'store'])->name('register_deposit');
|
//Route::post('register_deposit', [DepositController::class, 'store'])->name('register_deposit');
|
||||||
Route::post('update_comment', [CustomerController::class, 'updateComment'])->name('update_comment');
|
Route::post('update_comment', [CustomerController::class, 'updateComment'])->name('update_comment');
|
||||||
Route::post('register_purchase', [PurchaseController::class, 'store'])->name('register_purchase');
|
Route::post('register_purchase', [PurchaseController::class, 'store'])->name('register_purchase');
|
||||||
|
Route::post('customer-group', [CustomerGroupController::class, 'store'])->name('register_customer_group');
|
||||||
|
Route::post('add-to-customer-group/{id}', [CustomerGroupController::class, 'update'])->name('add_to_customer_group');
|
||||||
|
Route::delete('customer-group/{id}', [CustomerGroupController::class, 'destroy'])->name('delete_customer_group');
|
||||||
Route::delete('customer/{id}', [CustomerController::class, 'destroy'])->name('delete_customer');
|
Route::delete('customer/{id}', [CustomerController::class, 'destroy'])->name('delete_customer');
|
||||||
|
Route::put('customer/{id}', [CustomerController::class, 'edit'])->name('edit_customer');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::post('register_deposit', [DepositController::class, 'store'])->name('register_deposit')->middleware([ApiToken::class]);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,103 @@
|
||||||
|
|
||||||
use Illuminate\Foundation\Inspiring;
|
use Illuminate\Foundation\Inspiring;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use App\Models\Tableversion;
|
||||||
|
|
||||||
Artisan::command('inspire', function () {
|
Schedule::call(function () {
|
||||||
$this->comment(Inspiring::quote());
|
|
||||||
})->purpose('Display an inspiring quote');
|
$latestVersionParticipant = Tableversion::where('table', 'participants')->latest()->first();
|
||||||
|
$latestVersionVolunteer = Tableversion::where('table', 'volunteers')->latest()->first();
|
||||||
|
|
||||||
|
$client = new Client();
|
||||||
|
|
||||||
|
$responseVersions= $client->request(
|
||||||
|
'GET',
|
||||||
|
config('app.apilan_url') . "version",
|
||||||
|
[
|
||||||
|
'headers'=> [
|
||||||
|
'X-Api-Key' => config('app.apilan_key'),
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Content-Type' => 'application/json'
|
||||||
|
],
|
||||||
|
//'cert' => config('app.apilan_clientcert_path')
|
||||||
|
'cert' => Storage::disk('public')->path('lan.vbytes.se.pem')
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$versions = json_decode((string) $responseVersions->getBody(), true);
|
||||||
|
|
||||||
|
if ($latestVersionParticipant === null ) {
|
||||||
|
Tableversion::create([
|
||||||
|
'table' => 'participants',
|
||||||
|
'version' => $versions['participants'] - 1,
|
||||||
|
]);
|
||||||
|
$latestVersionParticipant = Tableversion::where('table', 'participants')->latest()->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $latestVersionVolunteer === null ) {
|
||||||
|
Tableversion::create([
|
||||||
|
'table' => 'volunteers',
|
||||||
|
'version' => $versions['volunteers'] - 1,
|
||||||
|
]);
|
||||||
|
$latestVersionVolunteer = Tableversion::where('table', 'volunteers')->latest()->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if($latestVersionParticipant->version < $versions['participants'] || $latestVersionVolunteer->version < $versions['volunteers'] ) {
|
||||||
|
$response = $client->request(
|
||||||
|
'GET',
|
||||||
|
config('app.apilan_url') . "data",
|
||||||
|
[
|
||||||
|
'headers'=> [
|
||||||
|
'X-Api-Key' => config('app.apilan_key'),
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Content-Type' => 'application/json'
|
||||||
|
],
|
||||||
|
//'cert' => config('app.apilan_clientcert_path')
|
||||||
|
'cert' => Storage::disk('public')->path('lan.vbytes.se.pem')
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$response_data = json_decode((string) $response->getBody(), true);
|
||||||
|
|
||||||
|
foreach ($response_data['participants'] as $participant) {
|
||||||
|
Customer::updateOrCreate(
|
||||||
|
['lan_id' => $participant['lan_id']],
|
||||||
|
[
|
||||||
|
'lan_id' => $participant['lan_id'],
|
||||||
|
'name' => $participant['first_name'] . " " . $participant['surname'],
|
||||||
|
'guardian_name' => "Anna",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($response_data['volunteers'] as $volunteer) {
|
||||||
|
Customer::updateOrCreate(
|
||||||
|
['lan_id' => $volunteer['lan_id']],
|
||||||
|
[
|
||||||
|
'lan_id' => $volunteer['lan_id'],
|
||||||
|
'name' => $volunteer['first_name'] . " " . $volunteer['surname'],
|
||||||
|
'guardian_name' => "Anna",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if($latestVersionParticipant->version < $versions['participants']) {
|
||||||
|
Tableversion::create([
|
||||||
|
'table' => 'participants',
|
||||||
|
'version' =>$latestVersionParticipant->version + 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($latestVersionVolunteer->version < $versions['volunteers']) {
|
||||||
|
Tableversion::create([
|
||||||
|
'table' => 'volunteers',
|
||||||
|
'version' =>$latestVersionVolunteer->version + 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
})->everyMinute();
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use Illuminate\Foundation\Application;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
use App\Http\Controllers\CustomerController;
|
use App\Http\Controllers\CustomerController;
|
||||||
|
use App\Http\Controllers\CustomerGroupController;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return Inertia::render('Auth/Login');
|
return Inertia::render('Auth/Login');
|
||||||
|
|
@ -12,6 +13,7 @@ Route::get('/', function () {
|
||||||
|
|
||||||
Route::get('/dashboard', [CustomerController::class, 'index'])->middleware(['auth', 'verified'])->name('dashboard');
|
Route::get('/dashboard', [CustomerController::class, 'index'])->middleware(['auth', 'verified'])->name('dashboard');
|
||||||
Route::get('/customer/{id}', [CustomerController::class, 'show'])->middleware(['auth', 'verified']);
|
Route::get('/customer/{id}', [CustomerController::class, 'show'])->middleware(['auth', 'verified']);
|
||||||
|
Route::get('/customer-groups', [CustomerGroupController::class, 'index'])->middleware(['auth', 'verified'])->name('customer-groups');
|
||||||
|
|
||||||
Route::get('/form', function () {
|
Route::get('/form', function () {
|
||||||
return Inertia::render('Form');
|
return Inertia::render('Form');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue