1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-20 14:54:15 +01:00

WIP: migrate machines list to react

This commit is contained in:
Sylvain 2021-06-16 18:03:06 +02:00
parent 7fa89c826a
commit 565002a124
8 changed files with 205 additions and 54 deletions

View File

@ -0,0 +1,11 @@
import apiClient from './clients/api-client';
import { AxiosResponse } from 'axios';
import { Machine } from '../models/machine';
export default class MachineAPI {
static async index (): Promise<Array<Machine>> {
const res: AxiosResponse<Array<Machine>> = await apiClient.get(`/api/machines`);
return res?.data;
}
}

View File

@ -1,16 +1,70 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { Machine } from '../../models/machine';
import { useTranslation } from 'react-i18next';
import { Loader } from '../base/loader';
interface MachineCardProps {
machine: Machine
machine: Machine,
onShowMachine: (machine: Machine) => void,
onReserveMachine: (machine: Machine) => void,
}
/**
* This component is a box showing the picture of the given machine and two buttons: one to start the reservation process
* and another to redirect the user to the machine description page.
*/
const MachineCard: React.FC<MachineCardProps> = ({ machine }) => {
const MachineCardComponent: React.FC<MachineCardProps> = ({ machine, onShowMachine, onReserveMachine }) => {
const { t } = useTranslation('public');
const machinePicture = (): ReactNode => {
if (!machine.machine_image) {
return (
<div className="machine-picture">
<img src="data:image/png;base64,"
data-src="holder.js/100%x100%/text:&#xf03e;/font:'Font Awesome 5 Free'/icon"
className="img-responsive"
alt={machine.name} />
</div>
);
}
return (
<div className="machine-picture" style={{ backgroundImage: `url(${machine.machine_image})` }} onClick={handleShowMachine} />
)
}
const handleReserveMachine = (): void => {
onReserveMachine(machine);
}
const handleShowMachine = (): void => {
onShowMachine(machine);
}
return (
<div/>
)
<div className="machine-card">
{machinePicture()}
<div className="machine-name">
{machine.name}
</div>
<div className="machine-actions">
{!machine.disabled && <button onClick={handleReserveMachine} className="reserve-button">
<i className="fas fa-bookmark" />
{t('app.public.machine_card.book')}
</button>}
<button onClick={handleShowMachine} className={`show-button ${machine.disabled ? 'single-button': ''}`}>
<i className="fas fa-eye" />
{t('app.public.machine_card.consult')}
</button>
</div>
</div>
);
}
export const MachineCard: React.FC<MachineCardProps> = ({ machine, onShowMachine, onReserveMachine }) => {
return (
<Loader>
<MachineCardComponent machine={machine} onShowMachine={onShowMachine} onReserveMachine={onReserveMachine} />
</Loader>
);
}

View File

@ -0,0 +1,47 @@
import React, { useEffect, useState } from 'react';
import { Machine } from '../../models/machine';
import { IApplication } from '../../models/application';
import { react2angular } from 'react2angular';
import { Loader } from '../base/loader';
import MachineAPI from '../../api/machine';
import { MachineCard } from './machine-card';
declare var Application: IApplication;
interface MachinesListProps {
onError: (message: string) => void,
onShowMachine: (machine: Machine) => void,
onReserveMachine: (machine: Machine) => void,
}
/**
* This component shows a list of all machines and allows filtering on that list.
*/
const MachinesList: React.FC<MachinesListProps> = ({ onError, onShowMachine, onReserveMachine }) => {
const [machines, setMachines] = useState<Array<Machine>>(null);
useEffect(() => {
MachineAPI.index()
.then(data => setMachines(data))
.catch(e => onError(e));
}, []);
return (
<div className="machines-list">
{machines && machines.map(machine => {
return <MachineCard machine={machine} onShowMachine={onShowMachine} onReserveMachine={onReserveMachine} />
})}
</div>
);
}
const MachinesListWrapper: React.FC<MachinesListProps> = ({ onError, onShowMachine, onReserveMachine }) => {
return (
<Loader>
<MachinesList onError={onError} onShowMachine={onShowMachine} onReserveMachine={onReserveMachine} />
</Loader>
);
}
Application.Components.component('machinesList', react2angular(MachinesListWrapper, ['onError', 'onShowMachine', 'onReserveMachine']));

View File

@ -50,5 +50,7 @@
@import "modules/edit-plan-category";
@import "modules/delete-plan-category";
@import "modules/plans-filter";
@import "modules/machines/machine-card";
@import "modules/machines/machines-list";
@import "app.responsive";

View File

@ -0,0 +1,75 @@
.machine-card {
background-color: #fff;
border: 1px solid #ddd;
border-radius: 6px;
margin: 0 15px 30px;
width: 30%;
min-width: 300px;
.machine-picture {
height: 250px;
background-size: cover;
background-position: center;
transition: opacity 0.5s ease;
cursor: pointer;
padding: 0;
color: #333333;
background-color: #f5f5f5;
border-color: #ddd;
border-bottom: 1px solid transparent;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.machine-name {
text-align: center;
padding: 15px;
font-size: 1.6rem;
text-transform: uppercase;
font-weight: 600;
color: #000;
margin: 0;
line-height: 1.8rem;
}
.machine-actions {
padding: 0;
background-color: #fff;
border-top: 1px solid #ddd;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
text-align: center;
display: flex;
& > button {
border: none !important;
padding: 15px 12px;
display: block;
width: 50%;
background-color: #fbfbfb;
margin-bottom: 0;
font-weight: normal;
text-align: center;
white-space: nowrap;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
font-size: 16px;
line-height: 1.5;
border-radius: 4px;
& > i {
margin-right: 5px;
}
&.reserve-button {
border-right: 1px solid #dddddd !important;
}
&.single-button {
width: 100%;
}
}
}
}

View File

@ -0,0 +1,4 @@
.machines-list {
display: flex;
flex-wrap: wrap;
}

View File

@ -20,7 +20,7 @@
</section>
<section class="m-lg machines-list"
<section class="m-lg"
ui-tour="machines"
ui-tour-backdrop="true"
ui-tour-template-url="'/shared/tour-step-template.html'"
@ -28,53 +28,8 @@
ui-tour-scroll-parent-id="content-main"
post-render="setupMachinesTour">
<div class="row">
<div class="col-md-3 form-group">
<div class="input-group m-l-lg m-b">
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
<select ng-model="machineFiltering" class="form-control">
<option ng-repeat="status in filterDisabled" value="{{status}}" translate>{{ 'app.public.machines_list.status_'+status }}</option>
</select>
</div>
</div>
<div class="col-md-3 col-md-offset-6 m-t-n row-centered" ng-if="isAuthorized(['admin', 'manager'])">
<a role="button" ui-sref="app.admin.calendar" class="btn btn-lg btn-default rounded m-t-sm text-sm">
<i class="fa fa-calendar-check-o m-r" aria-hidden="true"></i><span translate>{{ 'app.public.machines_list.new_availability' }}</span>
</a>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-lg-4 reservable-card" ng-class="{'disabled-reservable' : machine.disabled && machineFiltering === 'all'}" ng-repeat="machine in machines | filterDisabled:machineFiltering">
<div class="widget panel panel-default">
<div class="panel-heading picture" ng-if="!machine.machine_image" ng-click="showMachine(machine)">
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:'Font Awesome 5 Free'/icon" bs-holder class="img-responsive">
</div>
<div class="panel-heading picture" style="background-image:url({{machine.machine_image}})" ng-if="machine.machine_image" ng-click="showMachine(machine)">
</div>
<div class="panel-body">
<h1 class="text-center m-b">{{machine.name}}</h1>
</div>
<div class="panel-footer no-padder">
<div class="text-center clearfix">
<div class="col-sm-6 b-r no-padder">
<div class="btn btn-default btn-block no-b padder-v red reserve-button" ng-click="reserveMachine(machine, $event)" ng-hide="machine.disabled">
<i class="fa fa-bookmark m-r-xs"></i>
<span class="hidden-sm" translate>{{ 'app.public.machines_list.book' }}</span>
</div>
</div>
<div class="no-padder" ng-class="{'col-sm-6': !machine.disabled}">
<div class="btn btn-default btn-block padder-v no-b red show-button" ng-click="showMachine(machine)">
<i class="fa fa-eye m-r-xs"></i>
<span class="hidden-sm" translate>{{ 'app.shared.buttons.consult' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<machines-list on-show-machine="showMachine"
on-reserve-machine="reserveMachine">
</machines-list>
</section>

View File

@ -213,6 +213,9 @@ en:
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
machine_card:
book: "Book"
consult: "Consult"
#details of a machine
machines_show:
book_this_machine: "Book this machine"