Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/21 give the possibility to assign/unassign service to/from product #79

Draft
wants to merge 60 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
4fe11a9
🍱Added flinkey-product-service-admin-table component file
roswerk Feb 9, 2022
d82a6c7
🚧 Creates table with fetched data
roswerk Feb 9, 2022
8de3258
🚧 Toggles table columns
roswerk Feb 9, 2022
da5313e
🚧 Watch for products to be load, and loops over to identify products …
roswerk Feb 9, 2022
07d51da
🚧 Filters all services with no products and assigns it to unlinkedSer…
roswerk Feb 9, 2022
3ec2f32
🍱 Added Flinkey Modal file
roswerk Feb 9, 2022
cdb60b8
🚧 Create assign/un-assign modal
roswerk Feb 9, 2022
61d4679
🍱 Added service-dropdown file
roswerk Feb 9, 2022
041844f
🚧 Create dropdown with unlinked services
roswerk Feb 9, 2022
85676c0
🚧 Pass selected-service from dropdown to modal
roswerk Feb 9, 2022
c37fd6b
🚧 Set selected-service as value of dropdown and close it
roswerk Feb 9, 2022
5c76e06
🚧 Receive selected-service from dropdown and save it in dropdownService
roswerk Feb 9, 2022
5407caa
🚧 Added conditional Modal for link/unlink
roswerk Feb 9, 2022
64a4cab
🚧 Added service-dropdown to modal
roswerk Feb 9, 2022
ac717cf
🚧 Added linking functionality
roswerk Feb 9, 2022
766d5bc
🚧 Added unlinking functionality
roswerk Feb 9, 2022
d13ca03
🚧 Added close modal functionality
roswerk Feb 9, 2022
ca45046
🚧 Added link-services modal opener
roswerk Feb 9, 2022
1a4ee8c
🚧 Added unlink-services modal opener
roswerk Feb 9, 2022
62bc2f2
🚧 Added event-emitter to update data after link/unlink
roswerk Feb 9, 2022
f9f7c21
🚧 Added listener to know if new data was linked/unlinked from modal
roswerk Feb 9, 2022
fad091f
🚧 Added condition to re-render the DOM if new data was linked/unlinked
roswerk Feb 9, 2022
58cf87c
🔧 Added Customer-ID to defaultHeader
roswerk Feb 9, 2022
712a383
Merge branch 'main' into feature/21-give-the-possibility-to-assign/un…
BHuber-PlanB Feb 9, 2022
1b07695
🔧 Updated defaultHeader with Global customerId
roswerk Feb 10, 2022
be3cdc1
♻️ Replaced state naming from isOpen to isVisible
roswerk Feb 10, 2022
de7af88
♻️ Replaced arrow functions with regular functions
roswerk Feb 10, 2022
9c2ca53
🔥 Removed fetch services
roswerk Feb 10, 2022
c555d71
🚧 Replaced fetchProductToServices with fetchActiveServices
roswerk Feb 10, 2022
6b11a99
🚧 Set props to receive linkedServices and pass it to dropdown
roswerk Feb 10, 2022
c877402
🚧 Fetch unlinkedServices and display them in dropdown
roswerk Feb 10, 2022
c31d1f1
🚧 Added if check based on if link/unlink has been successful
roswerk Feb 10, 2022
ba6471a
Merge branch 'main' into feature/21-give-the-possibility-to-assign/un…
roswerk Feb 10, 2022
3ca05b3
Merge branch 'main' into feature/21-give-the-possibility-to-assign/un…
roswerk Feb 11, 2022
4bbb128
🚧 Changed conditional to display table-columns from state to props
roswerk Feb 11, 2022
5bbe18f
♻️ Improved messages in link/unlink modal
roswerk Feb 11, 2022
8e98d02
♻️ Improved code of service and product assign component
BHuber-PlanB Feb 13, 2022
d079b78
Merge branch 'main' into feature/21-give-the-possibility-to-assign/un…
BHuber-PlanB Feb 17, 2022
e757e42
♻️ Made product table easier to maintain
BHuber-PlanB Feb 20, 2022
137d2b6
🔖 Bumped package version
BHuber-PlanB Feb 20, 2022
0dc8c4b
♻️ Refactor dropdown to be reusable
roswerk Feb 21, 2022
f7710cb
♻️ added generic table component
BHuber-PlanB Feb 21, 2022
e768077
♻️ integrated generic table in service/product table
BHuber-PlanB Feb 21, 2022
3babd9e
🐛 fixed table value parsing
BHuber-PlanB Feb 21, 2022
7c27f0a
🐛 fixed some paths and filter for visibleColumns
BHuber-PlanB Feb 21, 2022
5a92b2c
🐛 fixed getFieldValue function provided with undefined field
BHuber-PlanB Feb 22, 2022
7044aa3
♻️ created generic dropdown component and integrated it into flinkey-…
BHuber-PlanB Feb 25, 2022
d1b6a96
✨ extended table component to support rendering passed template to cell
BHuber-PlanB Mar 4, 2022
4236b43
🚧 added action column cell template for product/service table
BHuber-PlanB Mar 4, 2022
ab3ba44
✨ added generic button component
BHuber-PlanB Mar 6, 2022
85faae5
🔥 removed focus border from generic button
BHuber-PlanB Mar 6, 2022
17fe258
✅ fixed keyfob catalog unit test
BHuber-PlanB Mar 6, 2022
590df09
✅ added button unit tests
BHuber-PlanB Mar 6, 2022
ea6fed9
✅ fixed utils unit tests
BHuber-PlanB Mar 6, 2022
7b7e449
♻️ improved event handler name
BHuber-PlanB Mar 6, 2022
ed02f50
✅ added unit tests for generic button and dropdown
BHuber-PlanB Mar 7, 2022
7488d3f
✅ added parent describe to unit test files
BHuber-PlanB Mar 7, 2022
3676b49
✅ added unit tests for table's getVisibility function
BHuber-PlanB Mar 7, 2022
7fedd8d
✅ added unit tests for table's getFieldValue function
BHuber-PlanB Mar 7, 2022
c3cbff0
✨ Added generic modal component
roswerk Mar 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
import { Component, h, State, Watch, Listen, Host } from '@stencil/core';
import { httpGet, HttpResponse } from '../../utils/utils';

@Component({
tag: 'flinkey-product-service-admin-table',
styleUrl: '../../utils/common.css',
shadow: true,
})
export class ProductServiceAdminTable {
@State() services: Array<any>;
@State() products: Array<any>;
@State() productsAndServices = [];
@State() activeServices = [];

// Services with no product assigned
@State() unlinkedServices: Array<any>;

// Column state managment
@State() idIsOpen: boolean = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these states?

@State() uniqueIdIsOpen: boolean = true;
@State() sNumberIsOpen: boolean = true;
@State() sapIsOpen: boolean = true;
@State() actServicesIsOpen: boolean = true;

// Modal
@State() linkingIsOpen: boolean = false;
@State() unlinkingIsOpen: boolean = false;
@State() selectedProduct: any;
@State() selectedService: number;

fetchProducts = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an arrow function? Because of this context?

return httpGet<string[]>('products')
.then((httpResponse: HttpResponse<string[]>) => {
this.products = httpResponse.parsedBody;
})
.catch(err => {
console.log(err);
});
};

fetchServices = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an arrow function? Because of this context?

return httpGet<string[]>('services')
.then((httpResponse: HttpResponse<string[]>) => {
this.services = httpResponse.parsedBody;
})
.catch(err => {
console.log(err);
});
};

fetchProductToService = async (productId: any) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an arrow function? Because of this context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have them fixed 👍

const path = `products/${productId.id}/services`;
return httpGet<any>(path)
.then((httpResponse: HttpResponse<any>) => {
const service = httpResponse.parsedBody;
this.productsAndServices = [...this.productsAndServices, { service, product: productId }];
this.activeServices = [...this.activeServices, { id: service.id }];
})
.catch(() => {
this.productsAndServices = [...this.productsAndServices, { product: productId }];
if (this.activeServices.length === 0) {
this.activeServices = [];
}
});
};

componentWillLoad() {
console.log('Will -> fetch');
this.fetchProducts();
this.fetchServices();
}

@Watch('products')
watchStateHandler() {
if (this.products) {
console.log('Will -> fetchP2S');
this.products.forEach(element => {
this.fetchProductToService(element);
});
}
}

// Check unlinked services
@Watch('activeServices')
activeServiceStateHandler() {
this.unlinkedServices = this.services.filter(({ id: unlinkedId1 }) => !this.activeServices.some(({ id: inactiveId }) => inactiveId === unlinkedId1));
}

// Modal - Close
@Listen('closeModal')
closeModal(value: any) {
this.linkingIsOpen = value.detail;
this.unlinkingIsOpen = value.detail;
}

// Overwritte all previous data
updateDOM = () => {
this.services = [];
this.products = [];
this.productsAndServices = [];
this.activeServices = [];
this.fetchProducts();
this.fetchServices();
};

// Modal - onPairing
@Listen('updateData')
updateDataHandler(value: any) {
if (value) {
this.updateDOM();
} else {
return;
}
}

linkingModalHandler(productId: any) {
this.linkingIsOpen = true;
this.selectedProduct = productId;
}

unlinkingModalHandler(productId: any, serviceId: any) {
this.unlinkingIsOpen = true;
this.selectedProduct = productId;
this.selectedService = serviceId;
}

render() {
return (
<Host class="flex flex-col">
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
<div class="flex flex-row items-center justify-center">
{this.idIsOpen && <div>ID</div>}
<button onClick={() => (this.idIsOpen = !this.idIsOpen)}>
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
</th>

<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
<div class="flex flex-row items-center justify-center">
{this.uniqueIdIsOpen && <div>Unique ID</div>}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should place the if statements on th and not on their content.

<button onClick={() => (this.uniqueIdIsOpen = !this.uniqueIdIsOpen)}>
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
</th>

<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
<div class="flex flex-row items-center justify-center">
{this.sNumberIsOpen && <div> Serial Number</div>}
<button onClick={() => (this.sNumberIsOpen = !this.sNumberIsOpen)}>
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
<div class="flex flex-row items-center justify-center">
{this.sapIsOpen && <div>Sap Number</div>}
<button onClick={() => (this.sapIsOpen = !this.sapIsOpen)}>
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
<div class="flex flex-row items-center justify-center">
{this.actServicesIsOpen && <div>Active Services</div>}
<button onClick={() => (this.actServicesIsOpen = !this.actServicesIsOpen)}>
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
</th>
<th scope="col" class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">
Functionen
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{this.productsAndServices &&
this.productsAndServices.map(product => {
return (
<tr class="text-center">
<td class="px-6 py-4 whitespace-wrap text-sm font-medium text-gray-900">{this.idIsOpen && `${product.product.id}`}</td>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should place the if statements on td and not on their content.

<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{this.uniqueIdIsOpen && `${product.product.uniqueId}`}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{this.sNumberIsOpen && `${product.product.serialNumber}`}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900"> {this.sapIsOpen && `${product.product.sapNumber}`}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{this.actServicesIsOpen && product.service !== undefined ? product.service.id : this.actServicesIsOpen && '-'}
</td>

<td>
{product.service !== undefined ? (
<button
type="button"
onClick={() => this.unlinkingModalHandler(product.product.id, product.service.id)}
class="px-6 py-4 mt-px whitespace-nowrap text-right text-sm font-medium bg-white text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500"
>
Uninstall
</button>
) : (
<button
type="button"
onClick={() => this.linkingModalHandler(product.product.id)}
class="px-6 py-4 mt-px whitespace-nowrap text-right text-sm font-medium bg-white text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500"
>
Link
</button>
)}
{this.linkingIsOpen && (
<flinkey-modal
modalTitle="Link a new Service to Product"
body="Here, you can link your a Service to a product. Go ahead a choose a service to link."
product={this.selectedProduct}
unlinkedServices={this.unlinkedServices}
/>
)}
{this.unlinkingIsOpen && (
<flinkey-modal
modalTitle="Unlink Service from Product"
body="Here, you can unlink your Service from a product. Go ahead a choose a service to link."
product={this.selectedProduct}
service={this.selectedService}
unlinkedServices={this.unlinkedServices}
/>
)}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</div>
</Host>
);
}
}
Loading