Agency events - First stable version
This commit is contained in:
parent
72017a64ac
commit
2436bf9488
|
@ -136,7 +136,7 @@ export default {
|
|||
addCreditFloatButton: `vn-float-button`,
|
||||
creditInput: `vn-input-number input[name="credit"]`,
|
||||
saveButton: `button[type=submit]`,
|
||||
firstCreditText: 'vn-client-credit-index vn-card > div vn-table vn-tbody > vn-tr'
|
||||
firstCreditText: 'vn-client-credit-index vn-card vn-table vn-tbody > vn-tr'
|
||||
},
|
||||
clientGreuge: {
|
||||
addGreugeFloatButton: `vn-float-button`,
|
||||
|
@ -144,13 +144,13 @@ export default {
|
|||
descriptionInput: `vn-textfield input[name="description"]`,
|
||||
typeAutocomplete: 'vn-autocomplete[ng-model="$ctrl.greuge.greugeTypeFk"]',
|
||||
saveButton: `button[type=submit]`,
|
||||
firstGreugeText: 'vn-client-greuge-index vn-card > div vn-table vn-tbody > vn-tr'
|
||||
firstGreugeText: 'vn-client-greuge-index vn-card vn-table vn-tbody > vn-tr'
|
||||
},
|
||||
clientMandate: {
|
||||
firstMandateText: 'vn-client-mandate vn-card > div vn-table vn-tbody > vn-tr'
|
||||
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
|
||||
},
|
||||
clientInvoices: {
|
||||
firstInvoiceText: 'vn-client-invoice vn-card > div vn-table vn-tbody > vn-tr'
|
||||
firstInvoiceText: 'vn-client-invoice vn-card vn-table vn-tbody > vn-tr'
|
||||
},
|
||||
clientLog: {
|
||||
logButton: 'vn-left-menu a[ui-sref="client.card.log"]',
|
||||
|
@ -307,7 +307,7 @@ export default {
|
|||
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) > vn-td > vn-one:nth-child(3) > div span:nth-child(3)',
|
||||
},
|
||||
ticketSummary: {
|
||||
header: 'vn-ticket-summary > vn-card > div > h5',
|
||||
header: 'vn-ticket-summary > vn-card > h5',
|
||||
state: 'vn-ticket-summary vn-label-value[label="State"] > section > span',
|
||||
route: 'vn-ticket-summary vn-label-value[label="Route"] > section > a',
|
||||
total: 'vn-ticket-summary vn-one.taxes > p:nth-child(3) > strong',
|
||||
|
@ -319,14 +319,14 @@ export default {
|
|||
popoverDiaryButton: '.vn-popover.shown vn-item-descriptor vn-icon[icon="icon-transaction"]',
|
||||
firstSaleQuantity: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3)',
|
||||
firstSaleDiscount: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6)',
|
||||
invoiceOutRef: 'vn-ticket-summary > vn-card > div > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(6) > section > span',
|
||||
invoiceOutRef: 'vn-ticket-summary > vn-card > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(6) > section > span',
|
||||
setOk: 'vn-ticket-summary vn-button[label="SET OK"] > button'
|
||||
},
|
||||
ticketsIndex: {
|
||||
openAdvancedSearchButton: 'vn-ticket-index vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"] input',
|
||||
newTicketButton: 'vn-ticket-index > a',
|
||||
searchResult: 'vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
|
||||
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
|
||||
searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)',
|
||||
searchTicketInput: `vn-ticket-index vn-textfield input`,
|
||||
|
@ -403,7 +403,7 @@ export default {
|
|||
saleDescriptorPopoverSummaryButton: '.vn-popover.shown vn-item-descriptor a[ui-sref="item.card.summary({id: $ctrl.item.id})"]',
|
||||
descriptorItemDiaryButton: 'vn-item-descriptor .quicklinks.ng-scope > vn-horizontal > a > vn-icon > i',
|
||||
newItemFromCatalogButton: 'vn-ticket-sale vn-float-button[icon="add"]',
|
||||
newItemButton: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-icon-button > button > vn-icon > i',
|
||||
newItemButton: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-one > vn-icon-button > button > vn-icon > i',
|
||||
moreMenu: 'vn-ticket-sale vn-tool-bar > vn-button-menu[vn-id="more-button"] > div > button',
|
||||
moreMenuCreateClaim: '.vn-popover.shown .vn-drop-down li[name="Add claim"]',
|
||||
moreMenuReserve: '.vn-popover.shown .vn-drop-down li[name="Mark as reserved"]',
|
||||
|
@ -443,7 +443,7 @@ export default {
|
|||
secondSaleQuantity: 'vn-ticket-sale vn-table vn-tr:nth-child(2) vn-input-number input',
|
||||
secondSaleConceptCell: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(6)',
|
||||
secondSaleConceptInput: 'vn-ticket-sale vn-table vn-tr:nth-child(2) > vn-td-editable.ng-isolate-scope.selected vn-textfield input',
|
||||
totalImport: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong',
|
||||
totalImport: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong',
|
||||
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
|
||||
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
|
||||
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]',
|
||||
|
@ -472,7 +472,7 @@ export default {
|
|||
zoneAutocomplete: 'vn-autocomplete[ng-model="$ctrl.zoneId"]',
|
||||
nextStepButton: 'vn-step-control .buttons > section:last-child vn-button',
|
||||
finalizeButton: 'vn-step-control .buttons > section:last-child button[type=submit]',
|
||||
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)',
|
||||
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > vn-horizontal > table > tfoot > tr > td:nth-child(4)',
|
||||
chargesReasonAutocomplete: 'vn-autocomplete[ng-model="$ctrl.ticket.option"]',
|
||||
},
|
||||
ticketComponents: {
|
||||
|
@ -481,7 +481,7 @@ export default {
|
|||
ticketRequests: {
|
||||
addRequestButton: 'vn-ticket-request-index > a > vn-float-button > button',
|
||||
request: 'vn-ticket-request-index vn-table vn-tr',
|
||||
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield input',
|
||||
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > vn-horizontal:nth-child(1) > vn-textfield input',
|
||||
atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[ng-model="$ctrl.ticketRequest.atenderFk"]',
|
||||
quantityInput: 'vn-ticket-request-create vn-input-number input[name=quantity]',
|
||||
priceInput: 'vn-ticket-request-create vn-input-number input[name=price]',
|
||||
|
@ -505,7 +505,7 @@ export default {
|
|||
firstVatTypeAutocomplete: 'vn-ticket-service vn-autocomplete[label="Tax class"]',
|
||||
fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]',
|
||||
newDescriptionInput: 'vn-ticket-service > vn-dialog vn-textfield[ng-model="$ctrl.newServiceType.name"] input',
|
||||
serviceLine: 'vn-ticket-service > form > vn-card > div > vn-one:nth-child(2) > vn-horizontal',
|
||||
serviceLine: 'vn-ticket-service > form > vn-card > vn-one:nth-child(2) > vn-horizontal',
|
||||
saveServiceButton: `button[type=submit]`,
|
||||
saveDescriptionButton: 'vn-ticket-service > vn-dialog[vn-id="createServiceTypeDialog"] > div > form > div.buttons > tpl-buttons > button'
|
||||
},
|
||||
|
@ -517,7 +517,7 @@ export default {
|
|||
},
|
||||
claimsIndex: {
|
||||
searchClaimInput: `vn-claim-index vn-textfield input`,
|
||||
searchResult: 'vn-claim-index vn-card > div > vn-table > div > vn-tbody > a',
|
||||
searchResult: 'vn-claim-index vn-card > vn-table > div > vn-tbody > a',
|
||||
searchButton: 'vn-claim-index vn-searchbar vn-icon[icon="search"]'
|
||||
},
|
||||
claimDescriptor: {
|
||||
|
@ -526,7 +526,7 @@ export default {
|
|||
acceptDeleteClaim: 'vn-claim-descriptor > vn-confirm[vn-id="confirm-delete-claim"] button[response="ACCEPT"]'
|
||||
},
|
||||
claimSummary: {
|
||||
header: 'vn-claim-summary > vn-card > div > h5',
|
||||
header: 'vn-claim-summary > vn-card > h5',
|
||||
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
|
||||
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"] textarea',
|
||||
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
|
||||
|
@ -535,7 +535,7 @@ export default {
|
|||
itemDescriptorPopoverItemDiaryButton: '.vn-popover.shown vn-item-descriptor a[href="#!/item/2/diary"]',
|
||||
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
||||
firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor div.quicklinks > a[href="#!/client/21/summary"]',
|
||||
firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
||||
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
||||
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
|
||||
},
|
||||
claimBasicData: {
|
||||
|
@ -545,19 +545,19 @@ export default {
|
|||
saveButton: `button[type=submit]`
|
||||
},
|
||||
claimDetail: {
|
||||
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(6) > span',
|
||||
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(6) > span',
|
||||
discountInput: '.vn-popover.shown vn-input-number[ng-model="$ctrl.newDiscount"] input',
|
||||
discoutPopoverMana: '.vn-popover.shown .content > div > vn-horizontal > h5',
|
||||
addItemButton: 'vn-claim-detail a vn-float-button',
|
||||
firstClaimableSaleFromTicket: 'vn-claim-detail > vn-dialog vn-tbody > vn-tr',
|
||||
claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr',
|
||||
claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr',
|
||||
firstItemQuantityInput: 'vn-claim-detail vn-tr:nth-child(1) vn-input-number[ng-model="saleClaimed.quantity"] input',
|
||||
totalClaimed: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > div > vn-label-value:nth-child(2) > section > span',
|
||||
secondItemDeleteButton: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(8) > vn-icon-button > button > vn-icon > i'
|
||||
totalClaimed: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-horizontal > div > vn-label-value:nth-child(2) > section > span',
|
||||
secondItemDeleteButton: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(8) > vn-icon-button > button > vn-icon > i'
|
||||
},
|
||||
claimDevelopment: {
|
||||
addDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-icon-button > button > vn-icon',
|
||||
firstDeleteDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > div > vn-vertical > form > vn-horizontal:nth-child(2) > vn-icon-button > button > vn-icon',
|
||||
addDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > vn-vertical > vn-one > vn-icon-button > button > vn-icon',
|
||||
firstDeleteDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > vn-vertical > form > vn-horizontal:nth-child(2) > vn-icon-button > button > vn-icon',
|
||||
firstClaimReasonAutocomplete: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimReasonFk"]',
|
||||
firstClaimResultAutocomplete: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimResultFk"]',
|
||||
firstClaimResponsibleAutocomplete: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimResponsibleFk"]',
|
||||
|
@ -580,7 +580,7 @@ export default {
|
|||
isPaidWithManaCheckbox: 'vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
||||
},
|
||||
ordersIndex: {
|
||||
searchResult: 'vn-order-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
|
||||
searchResult: 'vn-order-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
searchResultDate: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)',
|
||||
searchResultAddress: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)',
|
||||
searchOrderInput: `vn-order-index vn-textfield input`,
|
||||
|
@ -641,7 +641,7 @@ export default {
|
|||
volume: 'vn-route-descriptor vn-label-value[label="Volume"] > section > span'
|
||||
},
|
||||
routeSummary: {
|
||||
routeId: 'vn-route-summary > vn-card > div > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(1) > section > span'
|
||||
routeId: 'vn-route-summary > vn-card > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(1) > section > span'
|
||||
},
|
||||
routeBasicData: {
|
||||
workerAutoComplete: 'vn-route-basic-data vn-autocomplete[ng-model="$ctrl.route.workerFk"]',
|
||||
|
@ -671,57 +671,57 @@ export default {
|
|||
},
|
||||
workerTimeControl: {
|
||||
timeDialogInput: '.vn-dialog.shown [ng-model="$ctrl.newTime"]',
|
||||
mondayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button > button > vn-icon',
|
||||
tuesdayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(2) > vn-icon-button > button > vn-icon',
|
||||
wednesdayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(3) > vn-icon-button > button > vn-icon',
|
||||
thursdayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-icon-button > button > vn-icon',
|
||||
fridayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(5) > vn-icon-button > button > vn-icon',
|
||||
saturdayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(6) > vn-icon-button > button > vn-icon',
|
||||
sundayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(7) > vn-icon-button > button > vn-icon',
|
||||
mondayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button',
|
||||
tuesdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(2) > vn-icon-button',
|
||||
wednesdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(3) > vn-icon-button',
|
||||
thursdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-icon-button',
|
||||
fridayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(5) > vn-icon-button',
|
||||
saturdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(6) > vn-icon-button',
|
||||
sundayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(7) > vn-icon-button',
|
||||
confirmButton: 'vn-worker-time-control > vn-dialog > div > form > div.buttons > tpl-buttons > button',
|
||||
firstEntryOfMonday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > span',
|
||||
firstEntryOfTuesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > span',
|
||||
firstEntryOfWednesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > span',
|
||||
firstEntryOfThursday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(1) > span',
|
||||
firstEntryOfFriday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(1) > span',
|
||||
firstEntryOfSaturday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(1) > span',
|
||||
firstEntryOfSunday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(1) > span',
|
||||
secondEntryOfMonday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(2) > span',
|
||||
secondEntryOfTuesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(2) > span',
|
||||
secondEntryOfWednesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(2) > span',
|
||||
secondEntryOfThursday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(2) > span',
|
||||
secondEntryOfFriday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(2) > span',
|
||||
secondEntryOfSaturday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(2) > span',
|
||||
secondEntryOfSunday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(2) > span',
|
||||
thirdEntryOfMonday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > span',
|
||||
thirdEntryOfTuesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(3) > span',
|
||||
thirdEntryOfWednesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(3) > span',
|
||||
thirdEntryOfThursday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(3) > span',
|
||||
thirdEntryOfFriday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(3) > span',
|
||||
thirdEntryOfSaturday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(3) > span',
|
||||
thirdEntryOfSunday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(3) > span',
|
||||
fourthEntryOfMonday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(4) > span',
|
||||
fourthEntryOfTuesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(4) > span',
|
||||
fourthEntryOfWednesday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(4) > span',
|
||||
fourthEntryOfThursday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(4) > span',
|
||||
fourthEntryOfFriday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(4) > span',
|
||||
fourthEntryOfSaturday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(4) > span',
|
||||
fourthEntryOfSunday: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(4) > span',
|
||||
mondayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(1)',
|
||||
tuesdayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(2)',
|
||||
wednesdayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(3)',
|
||||
thursdayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(4)',
|
||||
fridayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(5)',
|
||||
saturdayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(6)',
|
||||
sundayWorkedHours: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(7)',
|
||||
weekWorkedHours: 'vn-worker-time-control > div > vn-side-menu > div > vn-vertical > vn-vertical > vn-label-value > section > span',
|
||||
nextMonthButton: 'vn-worker-time-control > div > vn-side-menu > div > vn-calendar > div > vn-horizontal > vn-auto:nth-child(3) > vn-icon',
|
||||
firstEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > span',
|
||||
firstEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > span',
|
||||
firstEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > span',
|
||||
firstEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(1) > span',
|
||||
firstEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(1) > span',
|
||||
firstEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(1) > span',
|
||||
firstEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(1) > span',
|
||||
secondEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(2) > span',
|
||||
secondEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(2) > span',
|
||||
secondEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(2) > span',
|
||||
secondEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(2) > span',
|
||||
secondEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(2) > span',
|
||||
secondEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(2) > span',
|
||||
secondEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(2) > span',
|
||||
thirdEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > span',
|
||||
thirdEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(3) > span',
|
||||
thirdEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(3) > span',
|
||||
thirdEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(3) > span',
|
||||
thirdEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(3) > span',
|
||||
thirdEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(3) > span',
|
||||
thirdEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(3) > span',
|
||||
fourthEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(4) > span',
|
||||
fourthEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(4) > span',
|
||||
fourthEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(4) > span',
|
||||
fourthEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(4) > span',
|
||||
fourthEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(4) > span',
|
||||
fourthEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(4) > span',
|
||||
fourthEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(4) > span',
|
||||
mondayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(1)',
|
||||
tuesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(2)',
|
||||
wednesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(3)',
|
||||
thursdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(4)',
|
||||
fridayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(5)',
|
||||
saturdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(6)',
|
||||
sundayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(7)',
|
||||
weekWorkedHours: 'vn-worker-time-control vn-side-menu vn-label-value > section > span',
|
||||
nextMonthButton: 'vn-worker-time-control vn-side-menu vn-calendar vn-button[icon=keyboard_arrow_right]',
|
||||
navigateBackToIndex: 'vn-worker-descriptor vn-icon[icon="chevron_left"]'
|
||||
},
|
||||
invoiceOutIndex: {
|
||||
searchInvoiceOutInput: `vn-invoice-out-index vn-textfield input`,
|
||||
searchButton: 'vn-invoice-out-index vn-searchbar vn-icon[icon="search"]',
|
||||
searchResult: 'vn-invoice-out-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
|
||||
searchResult: 'vn-invoice-out-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
},
|
||||
invoiceOutDescriptor: {
|
||||
moreMenu: 'vn-invoice-out-descriptor vn-icon-menu[icon=more_vert]',
|
||||
|
@ -732,6 +732,6 @@ export default {
|
|||
acceptBookingButton: 'vn-invoice-out-descriptor > vn-confirm[vn-id="bookConfirmation"] button[response="ACCEPT"]'
|
||||
},
|
||||
invoiceOutSummary: {
|
||||
bookedLabel: 'vn-invoice-out-summary > vn-card > div > vn-horizontal > vn-one > vn-label-value:nth-child(4) > section > span'
|
||||
bookedLabel: 'vn-invoice-out-summary > vn-card > vn-horizontal > vn-one > vn-label-value:nth-child(4) > section > span'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,82 +1,46 @@
|
|||
<div>
|
||||
<vn-horizontal class="header">
|
||||
<vn-auto>
|
||||
<vn-icon
|
||||
<div class="header">
|
||||
<vn-button
|
||||
icon="keyboard_arrow_left"
|
||||
class="pointer"
|
||||
ng-click="$ctrl.movePrevious($ctrl.skip)"
|
||||
ng-show="$ctrl.displayControls"/>
|
||||
</vn-icon>
|
||||
</vn-auto>
|
||||
<vn-one>
|
||||
<div>
|
||||
class="flat"
|
||||
ng-click="$ctrl.movePrevious()"
|
||||
translate-attr="::{title: 'Previous'}"
|
||||
ng-if="$ctrl.displayControls"/>
|
||||
</vn-button>
|
||||
<div class="title">
|
||||
<span translate>{{$ctrl.defaultDate | date: 'MMMM'}}</span>
|
||||
<span>{{$ctrl.defaultDate | date: 'yyyy'}}</span>
|
||||
<span ng-hide="::$ctrl.hideYear">{{$ctrl.defaultDate | date: 'yyyy'}}</span>
|
||||
</div>
|
||||
</vn-one>
|
||||
<vn-auto>
|
||||
<vn-icon
|
||||
<vn-button
|
||||
icon="keyboard_arrow_right"
|
||||
class="pointer"
|
||||
ng-click="$ctrl.moveNext($ctrl.skip)"
|
||||
ng-show="$ctrl.displayControls">
|
||||
</vn-icon>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
<vn-vertical class="body">
|
||||
<vn-horizontal class="weekdays">
|
||||
<section title="{{'Monday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(1)">
|
||||
<span>L</span>
|
||||
class="flat"
|
||||
ng-click="$ctrl.moveNext()"
|
||||
translate-attr="::{title: 'Next'}"
|
||||
ng-if="$ctrl.displayControls">
|
||||
</vn-button>
|
||||
</div>
|
||||
<div class="weekdays">
|
||||
<section
|
||||
ng-repeat="day in ::$ctrl.weekDays"
|
||||
translate-attr="::{title: day.name}"
|
||||
ng-click="$ctrl.selectWeekDay(day.index)">
|
||||
<span>{{::day.localeChar}}</span>
|
||||
</section>
|
||||
<section title="{{'Tuesday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(2)">
|
||||
<span>M</span>
|
||||
</section>
|
||||
<section title="{{'Wednesday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(3)">
|
||||
<span>X</span>
|
||||
</section>
|
||||
<section title="{{'Thursday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(4)">
|
||||
<span>J</span>
|
||||
</section>
|
||||
<section title="{{'Friday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(5)">
|
||||
<span>V</span>
|
||||
</section>
|
||||
<section title="{{'Saturday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(6)">
|
||||
<span>S</span>
|
||||
</section>
|
||||
<section title="{{'Sunday' | translate}}"
|
||||
ng-click="$ctrl.selectAll(0)">
|
||||
<span>D</span>
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="days">
|
||||
</div>
|
||||
<div
|
||||
class="days"
|
||||
ng-class="{'hide-contiguous': $ctrl.hideContiguous}">
|
||||
<section
|
||||
ng-repeat="day in $ctrl.days"
|
||||
class="day {{::$ctrl.getClass({$day: day.dated})}}"
|
||||
ng-class="::{primary: day.events.length > 0 || $ctrl.hasEvents({$day: day.dated})}">
|
||||
<div class="content">
|
||||
<div class="day-number"
|
||||
title="{{(day.eventName) | translate}}"
|
||||
ng-style="$ctrl.renderStyle(day.style)"
|
||||
ng-click="$ctrl.select($index)">
|
||||
{{::day.dated | date: 'd'}}
|
||||
</div>
|
||||
<div ng-if="day.events" class="events">
|
||||
<div ng-repeat="event in day.events" class="event"
|
||||
title="{{(event.description || event.name) | translate}}">
|
||||
<span class="chip ellipsize"
|
||||
ng-style="::$ctrl.renderStyle(event.style)">
|
||||
{{::event.name}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
class="day"
|
||||
ng-class="::$ctrl.getDayClasses(day)"
|
||||
vn-repeat-last
|
||||
on-last="$ctrl.repeatLast()">
|
||||
<div
|
||||
class="day-number"
|
||||
ng-click="$ctrl.select(day)">
|
||||
{{::day | date: 'd'}}
|
||||
</div>
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</div>
|
||||
</div>
|
|
@ -1,43 +1,26 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import FormInput from '../form-input';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Flat calendar.
|
||||
*
|
||||
* @property {Array} data Array of events
|
||||
* @property {Array} defaultDate Array of events
|
||||
* @property {Function} hasEvents Determines if an events exists for a day
|
||||
* @property {Function} getClass Class to apply to specific day
|
||||
* @event selection Emitted when day or weekday is selected
|
||||
* @event move Emitted when month changes
|
||||
*/
|
||||
export default class Calendar extends Component {
|
||||
constructor($element, $scope) {
|
||||
export default class Calendar extends FormInput {
|
||||
constructor($element, $scope, vnWeekDays) {
|
||||
super($element, $scope);
|
||||
this.events = [];
|
||||
this.weekDays = vnWeekDays.locales;
|
||||
this.defaultDate = new Date();
|
||||
this.displayControls = true;
|
||||
this.disabled = false;
|
||||
this.skip = 1;
|
||||
|
||||
this.window.addEventListener('resize', () => {
|
||||
this.checkSize();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the calendar
|
||||
* based on component height
|
||||
*/
|
||||
checkSize() {
|
||||
const height = this.$element[0].clientHeight;
|
||||
|
||||
if (height < 530)
|
||||
this.$element.addClass('small');
|
||||
else
|
||||
this.$element.removeClass('small');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial date
|
||||
* The initial date
|
||||
*
|
||||
* @return {Date} - Default date
|
||||
*/
|
||||
|
@ -45,11 +28,6 @@ export default class Calendar extends Component {
|
|||
return this._defaultDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new initial date
|
||||
*
|
||||
* @param {Date} value - New default date
|
||||
*/
|
||||
set defaultDate(value) {
|
||||
if (value) {
|
||||
value = new Date(value);
|
||||
|
@ -58,67 +36,10 @@ export default class Calendar extends Component {
|
|||
}
|
||||
|
||||
this._defaultDate = value;
|
||||
this.month = value.getMonth();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets events
|
||||
*
|
||||
* @param {Array} value - Array of events
|
||||
* @param {Date} event.dated - Day to add event
|
||||
* @param {String} event.name - Tooltip description
|
||||
* @param {String} event.className - ClassName style
|
||||
* @param {Object} event.style - Style properties
|
||||
*/
|
||||
set data(value) {
|
||||
if (!value) return;
|
||||
|
||||
this.events = [];
|
||||
|
||||
value.forEach(event => {
|
||||
event.dated = new Date(event.dated);
|
||||
event.dated.setHours(0, 0, 0, 0);
|
||||
this.events.push(event);
|
||||
});
|
||||
|
||||
if (this.defaultDate) {
|
||||
this.repaint();
|
||||
this.checkSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets current month date
|
||||
*/
|
||||
|
||||
get currentMonth() {
|
||||
return this.defaultDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets next month date
|
||||
*
|
||||
* @return {Date}
|
||||
*/
|
||||
get nextMonth() {
|
||||
const newDate = new Date(this.currentMonth);
|
||||
newDate.setMonth(this.currentMonth.getMonth() + 1);
|
||||
|
||||
return newDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets previous month date
|
||||
*
|
||||
* @return {Date}
|
||||
*/
|
||||
get previousMonth() {
|
||||
const newDate = new Date(this.currentMonth);
|
||||
newDate.setMonth(this.currentMonth.getMonth() - 1);
|
||||
|
||||
return newDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first day of month from a given date
|
||||
*
|
||||
|
@ -126,185 +47,113 @@ export default class Calendar extends Component {
|
|||
* @return {Integer}
|
||||
*/
|
||||
firstDay(date) {
|
||||
const newDate = new Date(
|
||||
return new Date(
|
||||
date.getFullYear(),
|
||||
date.getMonth(), 1);
|
||||
|
||||
return newDate;
|
||||
date.getMonth(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last day of month from a given date
|
||||
*
|
||||
* @param {Date} date - Origin date
|
||||
* @return {Integer}
|
||||
* Repaints the calendar.
|
||||
*/
|
||||
lastDay(date) {
|
||||
const newDate = new Date(
|
||||
date.getFullYear(),
|
||||
date.getMonth() + 1, 0);
|
||||
|
||||
return newDate;
|
||||
}
|
||||
|
||||
repaint() {
|
||||
const firstWeekday = this.firstDay(this.currentMonth).getDay();
|
||||
const previousLastDay = this.lastDay(this.previousMonth).getDate();
|
||||
const currentLastDay = this.lastDay(this.currentMonth).getDate();
|
||||
const maxFields = 42; // Max field limit
|
||||
const firstWeekday = this.firstDay(this.defaultDate).getDay() - 1;
|
||||
let weekdayOffset = firstWeekday >= 0 ? firstWeekday : 6;
|
||||
|
||||
let weekdayOffset = firstWeekday > 0 ? firstWeekday : 7;
|
||||
let dayPrevious = previousLastDay - (weekdayOffset - 2);
|
||||
let dayCurrent = 1;
|
||||
let dayNext = 1;
|
||||
let dayIndex = new Date(this.defaultDate.getTime());
|
||||
dayIndex.setDate(1 - weekdayOffset);
|
||||
|
||||
this.days = [];
|
||||
|
||||
for (let fieldIndex = 1; fieldIndex < maxFields; fieldIndex++) {
|
||||
// Insert previous month days
|
||||
if (fieldIndex < weekdayOffset) {
|
||||
const dated = new Date(
|
||||
this.previousMonth.getFullYear(),
|
||||
this.previousMonth.getMonth(), dayPrevious);
|
||||
|
||||
this.insertDay(dated, 'gray');
|
||||
dayPrevious++;
|
||||
}
|
||||
|
||||
// Insert current month days
|
||||
if (fieldIndex >= weekdayOffset && dayCurrent <= currentLastDay) {
|
||||
const dated = new Date(
|
||||
this.currentMonth.getFullYear(),
|
||||
this.currentMonth.getMonth(), dayCurrent);
|
||||
|
||||
this.insertDay(dated);
|
||||
dayCurrent++;
|
||||
}
|
||||
|
||||
// Insert next month days
|
||||
if (fieldIndex >= weekdayOffset && dayCurrent > currentLastDay) {
|
||||
const dated = new Date(
|
||||
this.nextMonth.getFullYear(),
|
||||
this.nextMonth.getMonth(), dayNext);
|
||||
|
||||
this.insertDay(dated, 'gray');
|
||||
dayNext++;
|
||||
}
|
||||
for (let i = 1; i <= 42; i++) {
|
||||
this.days.push(new Date(dayIndex.getTime()));
|
||||
dayIndex.setDate(dayIndex.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a date on an array of month days
|
||||
* Gets CSS classes to apply to the specified day.
|
||||
*
|
||||
* @param {Date} dated - Date of month
|
||||
* @param {String} className - Default class style
|
||||
* @param {Date} day The day
|
||||
* @return {Object} The CSS classes to apply
|
||||
*/
|
||||
insertDay(dated) {
|
||||
let events = this.events.filter(event => {
|
||||
return event.dated >= dated && event.dated <= dated;
|
||||
});
|
||||
getDayClasses(day) {
|
||||
let wday = day.getDay();
|
||||
let month = day.getMonth();
|
||||
|
||||
const params = {dated: dated, events: events /**/, style: {}};
|
||||
const isSaturday = dated.getDay() === 6;
|
||||
const isSunday = dated.getDay() === 0;
|
||||
const isCurrentMonth = dated.getMonth() === this.currentMonth.getMonth();
|
||||
const hasEvents = events.length > 0;
|
||||
let classes = {
|
||||
weekend: wday === 6 || wday === 0,
|
||||
previous: month < this.month,
|
||||
current: month == this.month,
|
||||
next: month > this.month,
|
||||
event: this.hasEvents({$day: day})
|
||||
};
|
||||
|
||||
if (isCurrentMonth && isSunday && !hasEvents)
|
||||
params.style = {color: '#999'};
|
||||
let userClass = this.getClass({$day: day});
|
||||
if (userClass) classes[userClass] = true;
|
||||
|
||||
if (isCurrentMonth && isSaturday && !hasEvents)
|
||||
params.style = {color: '#999'};
|
||||
|
||||
if (!isCurrentMonth)
|
||||
params.style = {opacity: '0.5'};
|
||||
|
||||
if (events.length > 0) {
|
||||
const eventStyle = events[0].style;
|
||||
const eventName = events[0].description || events[0].name;
|
||||
if (eventStyle)
|
||||
Object.assign(params.style, eventStyle);
|
||||
if (eventName)
|
||||
params.eventName = eventName;
|
||||
}
|
||||
|
||||
this.days.push(params);
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to next month(s)
|
||||
*
|
||||
* @param {Integer} skip - Months to skip at once
|
||||
*/
|
||||
moveNext(skip = 1) {
|
||||
let next = this.defaultDate.getMonth() + skip;
|
||||
this.defaultDate.setMonth(next);
|
||||
this.repaint();
|
||||
this.emit('moveNext');
|
||||
moveNext() {
|
||||
this.move(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to previous month(s)
|
||||
*
|
||||
* @param {Integer} skip - Months to skip at once
|
||||
*/
|
||||
movePrevious(skip = 1) {
|
||||
let previous = this.defaultDate.getMonth() - skip;
|
||||
this.defaultDate.setMonth(previous);
|
||||
this.repaint();
|
||||
this.emit('movePrevious');
|
||||
movePrevious() {
|
||||
this.move(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Day selection event
|
||||
* Moves @direction months backwards/forwards.
|
||||
*
|
||||
* @param {Integer} index - Index from days array
|
||||
* @param {Number} direction Negative to move backwards, positive forwards
|
||||
*/
|
||||
select(index) {
|
||||
if (this.disabled) return;
|
||||
let day = this.days[index].dated;
|
||||
move(direction) {
|
||||
let date = new Date(this.defaultDate.getTime());
|
||||
date.setMonth(date.getMonth() + direction);
|
||||
this.defaultDate = date;
|
||||
|
||||
this.repaint();
|
||||
this.emit('move', {$date: date});
|
||||
}
|
||||
|
||||
/*
|
||||
* Day selection event
|
||||
*/
|
||||
select(day) {
|
||||
if (!this.editable) return;
|
||||
this.field = day;
|
||||
this.emit('selection', {
|
||||
$days: [day],
|
||||
$type: 'day'
|
||||
});
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* WeekDay selection event
|
||||
*
|
||||
* @param {Integer} weekday - weekday index
|
||||
*/
|
||||
selectAll(weekday) {
|
||||
if (this.disabled) return;
|
||||
|
||||
selectWeekDay(weekday) {
|
||||
if (!this.editable) return;
|
||||
let days = [];
|
||||
for (let i in this.days) {
|
||||
const day = this.days[i].dated;
|
||||
if (day.getDay() === weekday && day.getMonth() == this.defaultDate.getMonth())
|
||||
for (let day of this.days) {
|
||||
if (day.getDay() === weekday && day.getMonth() == this.month)
|
||||
days.push(day);
|
||||
}
|
||||
this.field = days[0];
|
||||
this.emit('selection', {
|
||||
$days: days,
|
||||
$type: 'weekday',
|
||||
$weekday: weekday
|
||||
});
|
||||
}
|
||||
|
||||
renderStyle(style) {
|
||||
const normalizedStyle = {};
|
||||
|
||||
if (style) {
|
||||
const properties = Object.keys(style);
|
||||
properties.forEach(attribute => {
|
||||
const attrName = attribute.split(/(?=[A-Z])/).
|
||||
join('-').toLowerCase();
|
||||
|
||||
normalizedStyle[attrName] = style[attribute];
|
||||
});
|
||||
}
|
||||
|
||||
return normalizedStyle;
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
hasEvents() {
|
||||
|
@ -314,24 +163,31 @@ export default class Calendar extends Component {
|
|||
getClass() {
|
||||
return '';
|
||||
}
|
||||
|
||||
repeatLast() {
|
||||
if (!this.formatDay) return;
|
||||
|
||||
let days = this.element.querySelectorAll('.days > .day');
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
this.formatDay({
|
||||
$day: this.days[i],
|
||||
$element: days[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Calendar.$inject = ['$element', '$scope', 'vnWeekDays'];
|
||||
|
||||
Calendar.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.component('vnCalendar', {
|
||||
ngModule.vnComponent('vnCalendar', {
|
||||
template: require('./index.html'),
|
||||
controller: Calendar,
|
||||
bindings: {
|
||||
model: '<',
|
||||
data: '<?',
|
||||
defaultDate: '=?',
|
||||
onSelection: '&?',
|
||||
onMoveNext: '&?',
|
||||
onMovePrevious: '&?',
|
||||
hasEvents: '&?',
|
||||
getClass: '&?',
|
||||
formatDay: '&?',
|
||||
displayControls: '<?',
|
||||
disabled: '<?',
|
||||
skip: '<?'
|
||||
hideYear: '<?',
|
||||
hideContiguous: '<?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,6 +2,10 @@ describe('Component vnCalendar', () => {
|
|||
let controller;
|
||||
let $element;
|
||||
|
||||
let date = new Date();
|
||||
date.setHours(0, 0, 0, 0);
|
||||
date.setDate(1);
|
||||
|
||||
beforeEach(angular.mock.module('vnCore', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
@ -9,79 +13,55 @@ describe('Component vnCalendar', () => {
|
|||
beforeEach(inject(($compile, $rootScope) => {
|
||||
$element = $compile(`<vn-calendar></vn-calendar`)($rootScope);
|
||||
controller = $element.controller('vnCalendar');
|
||||
controller.defaultDate = new Date();
|
||||
controller.defaultDate = date;
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
$element.remove();
|
||||
});
|
||||
|
||||
describe('data() setter', () => {
|
||||
it(`should set an array of events and convert string dates to string object, then call repaint() method`, () => {
|
||||
spyOn(controller, 'repaint');
|
||||
|
||||
let currentDate = new Date().toString();
|
||||
controller.data = [
|
||||
{dated: currentDate, name: 'Event 1'},
|
||||
{dated: currentDate, name: 'Event 2'},
|
||||
];
|
||||
|
||||
expect(controller.events[0].dated instanceof Object).toBeTruthy();
|
||||
expect(controller.repaint).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('moveNext()', () => {
|
||||
it(`should shift to the next n months, then emit a 'moveNext' event`, () => {
|
||||
it(`should shift to the next month, then emit a 'move' event`, () => {
|
||||
spyOn(controller, 'emit');
|
||||
const currentMonth = controller.defaultDate.getMonth();
|
||||
let nextMonth = currentMonth + 1;
|
||||
let nextMonth = new Date(date.getTime());
|
||||
nextMonth.setMonth(nextMonth.getMonth() + 1);
|
||||
|
||||
controller.moveNext(1);
|
||||
controller.moveNext();
|
||||
|
||||
expect(controller.defaultDate.getMonth()).toEqual(nextMonth);
|
||||
expect(controller.emit).toHaveBeenCalledWith('moveNext');
|
||||
expect(controller.month).toEqual(nextMonth.getMonth());
|
||||
expect(controller.emit).toHaveBeenCalledWith('move', {$date: nextMonth});
|
||||
});
|
||||
});
|
||||
|
||||
describe('movePrevious()', () => {
|
||||
it(`should shift to the previous n months, then emit a 'movePrevious' event`, () => {
|
||||
it(`should shift to the previous month, then emit a 'move' event`, () => {
|
||||
spyOn(controller, 'emit');
|
||||
const currentMonth = controller.defaultDate.getMonth();
|
||||
let previousMonth = currentMonth - 1;
|
||||
let previousMonth = new Date(date.getTime());
|
||||
previousMonth.setMonth(previousMonth.getMonth() - 1);
|
||||
|
||||
controller.movePrevious(1);
|
||||
controller.movePrevious();
|
||||
|
||||
expect(controller.defaultDate.getMonth()).toEqual(previousMonth);
|
||||
expect(controller.emit).toHaveBeenCalledWith('movePrevious');
|
||||
expect(controller.month).toEqual(previousMonth.getMonth());
|
||||
expect(controller.emit).toHaveBeenCalledWith('move', {$date: previousMonth});
|
||||
});
|
||||
});
|
||||
|
||||
describe('select()', () => {
|
||||
it(`should return the selected element, then emit a 'selection' event`, () => {
|
||||
spyOn(controller, 'emit');
|
||||
const dated = new Date();
|
||||
const days = [{dated}];
|
||||
controller.days = days;
|
||||
controller.select(0);
|
||||
|
||||
const day = new Date();
|
||||
day.setHours(0, 0, 0, 0);
|
||||
controller.select(day);
|
||||
|
||||
let res = {
|
||||
$days: [dated],
|
||||
$days: [day],
|
||||
$type: 'day'
|
||||
};
|
||||
|
||||
expect(controller.field).toEqual(day);
|
||||
expect(controller.emit).toHaveBeenCalledWith('selection', res);
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderStyle()', () => {
|
||||
it(`should normalize CSS attributes`, () => {
|
||||
const result = controller.renderStyle({
|
||||
backgroundColor: 'red'
|
||||
});
|
||||
|
||||
expect(result['background-color']).toEqual('red');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,103 +1,97 @@
|
|||
@import "variables";
|
||||
|
||||
vn-calendar.small {
|
||||
.events {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
vn-calendar {
|
||||
display: block;
|
||||
|
||||
.header vn-one {
|
||||
& > div {
|
||||
& > .header {
|
||||
display: flex;
|
||||
margin-bottom: 0.5em;
|
||||
align-items: center;
|
||||
height: 2.4em;
|
||||
|
||||
& > .title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 0.2em 0;
|
||||
height: 1.5em
|
||||
}
|
||||
.weekdays {
|
||||
& > .vn-button {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
& > .weekdays {
|
||||
display: flex;
|
||||
color: $color-font-secondary;
|
||||
margin-bottom: 0.5em;
|
||||
padding: 0.5em 0;
|
||||
font-weight: bold;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.weekdays section {
|
||||
cursor: pointer
|
||||
}
|
||||
.weekdays section, .day {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
& > section {
|
||||
width: 14.28%;
|
||||
outline: 0;
|
||||
}
|
||||
.days {
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.day {
|
||||
.content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0
|
||||
}
|
||||
.day-number {
|
||||
transition: background-color 0.3s;
|
||||
text-align:center;
|
||||
float:inline-end;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
font-size: 0.85em;
|
||||
width:2.2em;
|
||||
height: 1.2em;
|
||||
padding: 0.5em 0;
|
||||
cursor: pointer;
|
||||
outline: 0
|
||||
}
|
||||
.day-number:hover {
|
||||
background-color: lighten($color-font-secondary, 20%);
|
||||
opacity: 0.8
|
||||
}
|
||||
}
|
||||
.day::after {
|
||||
content: "";
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
& > .days {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
& > .day {
|
||||
width: 14.28%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.weekend {
|
||||
color: $color-font-secondary;
|
||||
}
|
||||
.day.primary .day-number {
|
||||
&.previous,
|
||||
&.next {
|
||||
opacity: .5;
|
||||
}
|
||||
&.event .day-number {
|
||||
background-color: $color-main;
|
||||
color: $color-font-dark;
|
||||
}
|
||||
.events {
|
||||
margin-top: 0.5em;
|
||||
font-size: 0.6em
|
||||
}
|
||||
.events {
|
||||
color: $color-font-secondary;
|
||||
& > .day-number {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
width: 2.2em;
|
||||
height: 2.2em;
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
transition: background-color 300ms ease-in-out;
|
||||
|
||||
.event {
|
||||
margin-bottom: .1em;
|
||||
}
|
||||
}
|
||||
.chip {
|
||||
background-color: $color-main;
|
||||
color: $color-font-bg;
|
||||
display: inline-block;
|
||||
border-radius: .3em;
|
||||
padding: 0.3em .8em;
|
||||
max-width: 5em;
|
||||
}
|
||||
.day.gray {
|
||||
.day-number {
|
||||
color: $color-font-secondary
|
||||
}
|
||||
}
|
||||
.day.sunday {
|
||||
.day-number {
|
||||
color: $color-alert;
|
||||
font-weight: bold
|
||||
&:hover {
|
||||
background-color: lighten($color-font-secondary, 20%);
|
||||
opacity: .8
|
||||
}
|
||||
}
|
||||
}
|
||||
&.hide-contiguous > .day {
|
||||
&.previous,
|
||||
&.next {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.disabled,
|
||||
&.readonly {
|
||||
& > div {
|
||||
& > .weekdays > section {
|
||||
cursor: initial;
|
||||
}
|
||||
& > .days > .day > .day-number {
|
||||
cursor: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@ export default function directive() {
|
|||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
template: require('./card.html'),
|
||||
link: function($scope, $element, $attrs, $ctrl, $transclude) {
|
||||
$element.addClass('demo-card-wide vn-shadow bg-panel');
|
||||
$element[0].classList.add('vn-shadow', 'bg-panel');
|
||||
|
||||
$transclude($scope, function(clone) {
|
||||
angular.element($element[0].querySelector('div')).append(clone);
|
||||
$element.append(clone);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<h6>Debug info</h6>
|
||||
<ul>
|
||||
<li>
|
||||
{{$ctrl.env}}
|
||||
</li>
|
||||
<li>
|
||||
<span ng-class="{alert: $root.$$watchersCount > 500}">{{$root.$$watchersCount}}</span> watchers
|
||||
</li>
|
||||
</ul>
|
|
@ -0,0 +1,27 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Floating box displaying debugging information.
|
||||
* Enabled only in development environment.
|
||||
*/
|
||||
export default class Controller {
|
||||
constructor($element, $) {
|
||||
this.env = process.env.NODE_ENV || 'development';
|
||||
|
||||
if (this.env == 'development')
|
||||
this.interval = setInterval(() => $.$digest(), 2000);
|
||||
else
|
||||
$element[0].style.display = 'none';
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.component('vnDebugInfo', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
@import "variables";
|
||||
|
||||
vn-debug-info {
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
left: 1em;
|
||||
padding: 1em;
|
||||
min-width: 8em;
|
||||
background-color: #3f51b5;
|
||||
color: $color-font-dark;
|
||||
border-radius: 4px;
|
||||
z-index: 999;
|
||||
box-shadow: $shadow;
|
||||
transition: opacity 400ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
opacity: .5;
|
||||
}
|
||||
& > h6 {
|
||||
font-weight: normal;
|
||||
color: rgba(255, 255, 255, .5);
|
||||
font-size: 1em;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
& > li {
|
||||
margin-top: .2em;
|
||||
font-size: .95em;
|
||||
|
||||
& > span {
|
||||
padding: .05em .2em;
|
||||
border-radius: 4px;
|
||||
transition: background-color 200ms ease-in-out;
|
||||
|
||||
&.alert {
|
||||
background-color: $color-alert;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
tpl-body {
|
||||
display: block;
|
||||
min-width: 20em;
|
||||
min-width: 16em;
|
||||
}
|
||||
& > button.close {
|
||||
@extend %clickable;
|
||||
|
|
|
@ -153,10 +153,6 @@ export default class Field extends FormInput {
|
|||
fix.innerText = text || '';
|
||||
}
|
||||
|
||||
refreshTabIndex() {
|
||||
this.input.tabIndex = this.disabled ? -1 : this.tabIndex;
|
||||
}
|
||||
|
||||
onClick() {
|
||||
// if (event.defaultPrevented) return;
|
||||
// event.preventDefault();
|
||||
|
@ -182,14 +178,6 @@ export default class Field extends FormInput {
|
|||
this.input.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.input.focus();
|
||||
}
|
||||
|
||||
select() {
|
||||
this.input.select();
|
||||
}
|
||||
|
||||
buildInput(type) {
|
||||
let template = `<input type="${type}" ng-model="$ctrl.field"></input>`;
|
||||
this.input = this.$compile(template)(this.$)[0];
|
||||
|
|
|
@ -49,8 +49,9 @@ export default class FormInput extends Component {
|
|||
|
||||
set disabled(value) {
|
||||
this._disabled = boolTag(value);
|
||||
this.input.disabled = this._disabled;
|
||||
this.classList.toggle('disabled', this._disabled);
|
||||
if (this.input)
|
||||
this.input.disabled = this._disabled;
|
||||
this.refreshTabIndex();
|
||||
}
|
||||
|
||||
|
@ -60,8 +61,9 @@ export default class FormInput extends Component {
|
|||
|
||||
set readonly(value) {
|
||||
this._readonly = boolTag(value);
|
||||
this.input.readOnly = this._readonly;
|
||||
this.classList.toggle('readonly', this._readonly);
|
||||
if (this.input)
|
||||
this.input.readOnly = this._readonly;
|
||||
}
|
||||
|
||||
get readonly() {
|
||||
|
@ -77,16 +79,24 @@ export default class FormInput extends Component {
|
|||
return this._tabIndex;
|
||||
}
|
||||
|
||||
get inputEl() {
|
||||
return this.input || this.element;
|
||||
}
|
||||
|
||||
get editable() {
|
||||
return !(this.readonly || this.disabled);
|
||||
}
|
||||
|
||||
select() {
|
||||
this.input.select();
|
||||
this.inputEl.select();
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.input.focus();
|
||||
this.inputEl.focus();
|
||||
}
|
||||
|
||||
refreshTabIndex() {
|
||||
this.element.tabIndex = this.disabled ? -1 : this.tabIndex;
|
||||
this.inputEl.tabIndex = this.disabled ? -1 : this.tabIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import './check';
|
|||
import './chip';
|
||||
import './data-viewer';
|
||||
import './date-picker';
|
||||
import './debug-info';
|
||||
import './field';
|
||||
import './float-button';
|
||||
import './icon-menu';
|
||||
|
@ -44,3 +45,4 @@ import './td-editable';
|
|||
import './textarea';
|
||||
import './th';
|
||||
import './treeview';
|
||||
import './wday-picker';
|
||||
|
|
|
@ -18,32 +18,13 @@ export default class Toggle extends FormInput {
|
|||
element.classList.add('vn-toggle');
|
||||
}
|
||||
|
||||
set disabled(value) {
|
||||
this._disabled = value;
|
||||
this.classList.toggle('disabled', Boolean(value));
|
||||
this.refreshTabIndex();
|
||||
}
|
||||
|
||||
get disabled() {
|
||||
return this._disabled;
|
||||
}
|
||||
|
||||
set readonly(value) {
|
||||
this._readonly = value;
|
||||
this.classList.toggle('readonly', Boolean(value));
|
||||
}
|
||||
|
||||
get readonly() {
|
||||
return this._readonly;
|
||||
}
|
||||
|
||||
onKeydown(event) {
|
||||
if (event.code == 'Space')
|
||||
this.onClick(event);
|
||||
}
|
||||
|
||||
onClick(event) {
|
||||
if (this.disabled || event.defaultPrevented)
|
||||
if (!this.editable || event.defaultPrevented)
|
||||
return true;
|
||||
|
||||
event.preventDefault();
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
<span
|
||||
ng-repeat="day in $ctrl.days"
|
||||
translate-attr="::{title: day.name}"
|
||||
ng-class="{marked: $ctrl.field[day.code]}"
|
||||
ng-click="$ctrl.field[day.code] = !$ctrl.field[day.code]">
|
||||
{{day.localeChar}}
|
||||
</span>
|
|
@ -0,0 +1,17 @@
|
|||
import ngModule from '../../module';
|
||||
import FormInput from '../form-input';
|
||||
import './style.scss';
|
||||
|
||||
export default class WdayPicker extends FormInput {
|
||||
constructor($element, $scope, vnWeekDays) {
|
||||
super($element, $scope);
|
||||
this.input = {};
|
||||
this.days = vnWeekDays.locales;
|
||||
}
|
||||
}
|
||||
WdayPicker.$inject = ['$element', '$scope', 'vnWeekDays'];
|
||||
|
||||
ngModule.vnComponent('vnWdayPicker', {
|
||||
template: require('./index.html'),
|
||||
controller: WdayPicker
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
@import "effects";
|
||||
|
||||
vn-wday-picker {
|
||||
margin-top: $spacing-sm;
|
||||
margin-bottom: $spacing-md;
|
||||
text-align: center;
|
||||
|
||||
& > span {
|
||||
@extend %clickable;
|
||||
border-radius: 50%;
|
||||
padding: .4em;
|
||||
margin: .2em;
|
||||
display: inline-flex;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
background-color: rgba(0, 0, 0, .05);
|
||||
|
||||
&.marked {
|
||||
background: $color-main;
|
||||
color: $color-font-dark;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,3 +6,4 @@ import './token';
|
|||
import './modules';
|
||||
import './interceptor';
|
||||
import './config';
|
||||
import './week-days';
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class WeekDays {
|
||||
constructor($translate) {
|
||||
this.$translate = $translate;
|
||||
|
||||
this.days = [
|
||||
{
|
||||
code: 'sun',
|
||||
name: 'Sunday'
|
||||
}, {
|
||||
code: 'mon',
|
||||
name: 'Monday'
|
||||
}, {
|
||||
code: 'tue',
|
||||
name: 'Tuesday'
|
||||
}, {
|
||||
code: 'wed',
|
||||
name: 'Wednesday'
|
||||
}, {
|
||||
code: 'thu',
|
||||
name: 'Thursday'
|
||||
}, {
|
||||
code: 'fri',
|
||||
name: 'Friday'
|
||||
}, {
|
||||
code: 'sat',
|
||||
name: 'Saturday'
|
||||
}
|
||||
];
|
||||
|
||||
this.map = {};
|
||||
for (let i = 0; i < this.days.length; i++) {
|
||||
let day = this.days[i];
|
||||
day.index = i;
|
||||
day.char = day.name.substr(0, 1);
|
||||
day.abr = day.name.substr(0, 3);
|
||||
this.map[day.code] = day;
|
||||
}
|
||||
|
||||
this.getLocales();
|
||||
}
|
||||
|
||||
getLocales() {
|
||||
for (let day of this.days) {
|
||||
let locale = this.$translate.instant(day.name);
|
||||
Object.assign(day, {
|
||||
locale,
|
||||
localeChar: locale.substr(0, 1),
|
||||
localeAbr: locale.substr(0, 3)
|
||||
});
|
||||
}
|
||||
|
||||
this.localeCodes = [
|
||||
'mon',
|
||||
'tue',
|
||||
'wed',
|
||||
'thu',
|
||||
'fri',
|
||||
'sat',
|
||||
'sun'
|
||||
];
|
||||
|
||||
this.locales = [];
|
||||
for (let code of this.localeCodes)
|
||||
this.locales.push(this.map[code]);
|
||||
}
|
||||
}
|
||||
WeekDays.$inject = ['$translate'];
|
||||
|
||||
ngModule.service('vnWeekDays', WeekDays);
|
|
@ -42,13 +42,13 @@
|
|||
h1, h2, h3, h4, h5, h6 {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: .2em;
|
||||
margin-bottom: .3em;
|
||||
}
|
||||
|
||||
/* Colors */
|
||||
|
||||
.text-primary {
|
||||
color: $color-font;
|
||||
color: $color-main;
|
||||
}
|
||||
.text-secondary {
|
||||
color: $color-font-secondary;
|
||||
|
|
|
@ -26,3 +26,4 @@
|
|||
<vn-home></vn-home>
|
||||
</div>
|
||||
<vn-snackbar vn-id="snackbar"></vn-snackbar>
|
||||
<vn-debug-info></vn-debug-info>
|
|
@ -18,6 +18,9 @@ vn-main-menu {
|
|||
vertical-align: middle;
|
||||
font-weight: bold;
|
||||
margin-right: .2em;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
& > .vn-button {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
margin: 0 auto;
|
||||
max-width: 950px;
|
||||
|
||||
& > div {
|
||||
& > h5 {
|
||||
padding: $spacing-sm;
|
||||
border: none;
|
||||
|
@ -49,7 +48,6 @@
|
|||
margin-bottom: .3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
p:after {
|
||||
content: ' ';
|
||||
overflow: hidden;
|
||||
|
|
|
@ -61,11 +61,11 @@ vn-bg-title {
|
|||
}
|
||||
.totalBox {
|
||||
border: 1px solid #CCC;
|
||||
text-align: right !important;
|
||||
text-align: right;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 18px;
|
||||
max-width: 12em;
|
||||
padding: $spacing-md;
|
||||
max-width: 14em;
|
||||
}
|
||||
.form {
|
||||
height: 100%;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
width: 28em;
|
||||
overflow: hidden;
|
||||
|
||||
& > vn-card > div {
|
||||
& > vn-card {
|
||||
display: flex;
|
||||
height: 12em;
|
||||
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
<vn-card>
|
||||
<div class="header">
|
||||
<vn-button
|
||||
icon="navigate_before"
|
||||
ng-click="$ctrl.step(-1)"
|
||||
class="flat">
|
||||
</vn-button>
|
||||
<span>{{$ctrl.firstDay | date:'MMMM yyyy'}} - {{$ctrl.lastDay | date:'MMMM yyyy'}}</span>
|
||||
<vn-button
|
||||
icon="navigate_next"
|
||||
ng-click="$ctrl.step(1)"
|
||||
class="flat">
|
||||
</vn-button>
|
||||
</div>
|
||||
<div class="calendars vn-pa-md">
|
||||
<vn-calendar
|
||||
vn-id="stMonth"
|
||||
skip="2"
|
||||
has-events="$ctrl.hasEvents($day)"
|
||||
get-class="$ctrl.getClass($day)"
|
||||
on-selection="$ctrl.onSelection($days, $type, $weekday)"
|
||||
on-move-next="ndMonth.moveNext(2)"
|
||||
on-move-previous="ndMonth.movePrevious(2)"
|
||||
vn-acl="deliveryBoss"
|
||||
class="vn-pa-md">
|
||||
</vn-calendar>
|
||||
<vn-calendar
|
||||
vn-id="ndMonth"
|
||||
skip="2"
|
||||
has-events="$ctrl.hasEvents($day)"
|
||||
get-class="$ctrl.getClass($day)"
|
||||
on-selection="$ctrl.onSelection($days, $type, $weekday)"
|
||||
default-date="$ctrl.ndMonthDate"
|
||||
vn-acl="deliveryBoss"
|
||||
ng-repeat="date in $ctrl.months track by date.getTime()"
|
||||
default-date="date"
|
||||
display-controls="false"
|
||||
class="vn-pa-md">
|
||||
hide-contiguous="true"
|
||||
has-events="$ctrl.hasEvents($day)"
|
||||
get-class="$ctrl.getClass($day)"
|
||||
on-selection="$ctrl.onSelection($days, $type, $weekday)"
|
||||
class="vn-pa-md"
|
||||
style="min-width: 250px; flex: 1;">
|
||||
</vn-calendar>
|
||||
</div>
|
||||
</vn-card>
|
|
@ -5,96 +5,151 @@ import './style.scss';
|
|||
class Controller extends Section {
|
||||
constructor($el, $, $t, $http, $state) {
|
||||
super($el, $, $t, $http, $state);
|
||||
this.nMonths = 4;
|
||||
|
||||
this.excls = {};
|
||||
this.resetEvents();
|
||||
this.ndMonthDate = new Date();
|
||||
this.ndMonthDate.setMonth(this.ndMonthDate.getMonth() + 1);
|
||||
let date = new Date();
|
||||
date.setDate(1);
|
||||
date.setHours(0, 0, 0, 0);
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
get date() {
|
||||
return this._date;
|
||||
}
|
||||
|
||||
set date(value) {
|
||||
this._date = value;
|
||||
let stamp = value.getTime();
|
||||
|
||||
let firstDay = new Date(stamp);
|
||||
firstDay.setDate(1);
|
||||
this.firstDay = firstDay;
|
||||
|
||||
let lastDay = new Date(stamp);
|
||||
lastDay.setMonth(lastDay.getMonth() + this.nMonths);
|
||||
lastDay.setDate(0);
|
||||
this.lastDay = lastDay;
|
||||
|
||||
this.months = [];
|
||||
for (let i = 0; i < this.nMonths; i++) {
|
||||
let monthDate = new Date(stamp);
|
||||
monthDate.setMonth(value.getMonth() + i);
|
||||
this.months.push(monthDate);
|
||||
}
|
||||
|
||||
this.refreshEvents();
|
||||
}
|
||||
|
||||
step(direction) {
|
||||
let date = new Date(this.date.getTime());
|
||||
date.setMonth(date.getMonth() + (this.nMonths * direction));
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
set data(value) {
|
||||
this._data = value;
|
||||
|
||||
value = value || {};
|
||||
this.events = value.events;
|
||||
this.exclusions = value.exclusions;
|
||||
|
||||
if (this.events) {
|
||||
let codes = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||
for (event of this.events) {
|
||||
if (!event.weekDays) continue;
|
||||
let weekDays = event.weekDays.split(',');
|
||||
event.wdays = [];
|
||||
for (let wday of weekDays) {
|
||||
let index = codes.indexOf(wday);
|
||||
if (index !== -1) event.wdays[index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.refreshEvents();
|
||||
|
||||
let calendars = this.element.querySelectorAll('vn-calendar');
|
||||
for (let calendar of calendars)
|
||||
calendar.$ctrl.repaint();
|
||||
}
|
||||
|
||||
refreshEvents() {
|
||||
function getDate(date) {
|
||||
return date && new Date(date).setHours(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
let exclusionsMap = {};
|
||||
if (this.exclusions) {
|
||||
for (let exclusion of this.exclusions)
|
||||
exclusionsMap[getDate(exclusion.day)] = exclusion;
|
||||
}
|
||||
|
||||
this.days = {};
|
||||
let day = new Date(this.firstDay.getTime());
|
||||
|
||||
while (day < this.lastDay) {
|
||||
let stamp = day.getTime();
|
||||
let wday = day.getDay();
|
||||
let dayEvents = [];
|
||||
|
||||
if (this.events) {
|
||||
for (let event of this.events) {
|
||||
let match;
|
||||
let from = getDate(event.from);
|
||||
let to = getDate(event.to);
|
||||
|
||||
if (event.from && event.to) {
|
||||
match = stamp >= from && stamp <= to
|
||||
&& event.wdays[wday];
|
||||
} else if (event.from)
|
||||
match = from == stamp;
|
||||
else
|
||||
match = event.wdays[wday];
|
||||
|
||||
if (match)
|
||||
dayEvents.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
let exclusion = exclusionsMap[stamp];
|
||||
|
||||
if (dayEvents.length || exclusion) {
|
||||
let dayData = {};
|
||||
if (dayEvents.length) dayData.events = dayEvents;
|
||||
if (exclusion) dayData.exclusion = exclusion;
|
||||
this.days[stamp] = dayData;
|
||||
}
|
||||
|
||||
day.setDate(day.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
onSelection($days, $type, $weekday) {
|
||||
this.emit('selection', {$days, $type, $weekday});
|
||||
let $data = [];
|
||||
for (let day of $days) {
|
||||
let dayData = this.days[day.getTime()];
|
||||
if (dayData) $data.push(dayData);
|
||||
}
|
||||
|
||||
resetEvents() {
|
||||
this.wdays = [];
|
||||
this.days = {};
|
||||
this.ranges = [];
|
||||
}
|
||||
|
||||
get events() {
|
||||
return this._events;
|
||||
}
|
||||
|
||||
set events(value) {
|
||||
this._events = value;
|
||||
this.resetEvents();
|
||||
if (!value) return;
|
||||
|
||||
function setWdays(wdays, weekDays) {
|
||||
let codes = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||
if (!weekDays) return [];
|
||||
weekDays = weekDays.split(',');
|
||||
for (let wday of weekDays)
|
||||
wdays[codes.indexOf(wday)] = true;
|
||||
return wdays;
|
||||
}
|
||||
|
||||
for (let event of value) {
|
||||
if (event.from && event.to) {
|
||||
this.ranges.push({
|
||||
from: new Date(event.from).setHours(0, 0, 0, 0),
|
||||
to: new Date(event.to).setHours(0, 0, 0, 0),
|
||||
wdays: setWdays([], event.weekDays)
|
||||
this.emit('selection', {
|
||||
$days,
|
||||
$type,
|
||||
$weekday,
|
||||
$data
|
||||
});
|
||||
} else if (event.from) {
|
||||
let day = new Date(event.from).setHours(0, 0, 0, 0);
|
||||
this.days[day] = true;
|
||||
} else
|
||||
setWdays(this.wdays, event.weekDays);
|
||||
}
|
||||
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
get exclusions() {
|
||||
return this._exclusions;
|
||||
}
|
||||
|
||||
set exclusions(value) {
|
||||
this._exclusions = value;
|
||||
this.excls = {};
|
||||
if (!value) return;
|
||||
|
||||
value.forEach(exclusion => {
|
||||
let day = new Date(exclusion.day).setHours(0, 0, 0, 0);
|
||||
this.excls[day] = true;
|
||||
});
|
||||
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
hasRange(time, wday) {
|
||||
let range = this.ranges.find(e => e.from <= time && e.to >= time);
|
||||
return range && range.wdays[wday];
|
||||
}
|
||||
|
||||
hasEvents(day) {
|
||||
let time = day.getTime();
|
||||
let wday = day.getDay();
|
||||
return this.wdays[wday]
|
||||
|| this.days[time]
|
||||
|| this.hasRange(time, wday);
|
||||
return this.days[day.getTime()] != null;
|
||||
}
|
||||
|
||||
getClass(day) {
|
||||
if (this.excls[day.getTime()])
|
||||
return 'excluded';
|
||||
}
|
||||
|
||||
repaint() {
|
||||
this.$.stMonth.repaint();
|
||||
this.$.ndMonth.repaint();
|
||||
let dayData = this.days[day.getTime()];
|
||||
return dayData && dayData.exclusion ? 'excluded' : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +157,6 @@ ngModule.component('vnZoneCalendar', {
|
|||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
events: '<?',
|
||||
exclusions: '<?'
|
||||
data: '<?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,13 +1,40 @@
|
|||
@import "variables";
|
||||
|
||||
vn-zone-calendar {
|
||||
vn-calendar .day {
|
||||
&.primary .day-number {
|
||||
display: block;
|
||||
|
||||
& > vn-card {
|
||||
& > .header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: $color-main;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
height: 45px;
|
||||
|
||||
& > .vn-button {
|
||||
color: inherit;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
& > .calendars {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
& > vn-calendar {
|
||||
max-width: 18em;
|
||||
|
||||
.day {
|
||||
&.event .day-number {
|
||||
background-color: $color-success;
|
||||
}
|
||||
&.excluded .day-number {
|
||||
background-color: $color-alert;
|
||||
color: $color-font-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
<div style="margin: 0 auto; max-width: 40em;">
|
||||
<div class="vn-w-md">
|
||||
<form ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-md">
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
|
@ -32,16 +31,13 @@
|
|||
ng-model="$ctrl.params.postCode">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Query"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
<vn-card class="vn-pa-md vn-mt-md">
|
||||
<vn-zone-calendar
|
||||
events="events.events"
|
||||
exclusions="events.exclusions">
|
||||
data="data"
|
||||
class="vn-mt-md">
|
||||
</vn-zone-calendar>
|
||||
</vn-card>
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@ class Controller {
|
|||
|
||||
onSubmit() {
|
||||
this.$http.get(`/api/Zones/getEvents`, {params: this.params})
|
||||
.then(res => this.$.events = res.data);
|
||||
.then(res => this.$.data = res.data);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$scope', '$http'];
|
||||
|
|
|
@ -1,27 +1,60 @@
|
|||
<div class="main-with-right-menu">
|
||||
<vn-data-viewer
|
||||
<vn-zone-calendar
|
||||
id="calendar"
|
||||
data="data"
|
||||
is-loading="!data"
|
||||
on-selection="$ctrl.onSelection($days, $type, $weekday, $data)"
|
||||
class="vn-w-md">
|
||||
</vn-zone-calendar>
|
||||
</div>
|
||||
<vn-side-menu side="right">
|
||||
<div class="vn-pa-md">
|
||||
<h6
|
||||
class="text-secondary"
|
||||
style="font-weight: normal;"
|
||||
translate>
|
||||
Edit mode
|
||||
</h6>
|
||||
<vn-vertical>
|
||||
<vn-radio
|
||||
label="Include"
|
||||
val="include"
|
||||
ng-model="$ctrl.editMode">
|
||||
</vn-radio>
|
||||
<vn-radio
|
||||
label="Exclude"
|
||||
val="exclude"
|
||||
ng-model="$ctrl.editMode">
|
||||
</vn-radio>
|
||||
</vn-vertical>
|
||||
</div>
|
||||
<h6
|
||||
class="text-secondary vn-px-md"
|
||||
style="font-weight: normal;"
|
||||
translate>
|
||||
Events
|
||||
</h6>
|
||||
<vn-data-viewer
|
||||
data="data.events"
|
||||
is-loading="!data.events"
|
||||
class="vn-w-sm">
|
||||
<vn-card>
|
||||
<div class="vn-list">
|
||||
<a
|
||||
ng-repeat="row in data"
|
||||
ng-repeat="row in data.events"
|
||||
translate-attr="{title: 'Edit'}"
|
||||
ng-click="$ctrl.onEdit(row, $event)"
|
||||
ng-click="$ctrl.onEditClick(row, $event)"
|
||||
class="vn-list-item">
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<div
|
||||
ng-if="::row.from && !row.to"
|
||||
class="vn-mb-sm">
|
||||
{{::row.from | date:'dd/MM/yyyy'}}
|
||||
{{::row.from | date:'dd/MM/yy'}}
|
||||
</div>
|
||||
<div
|
||||
ng-if="::!row.from || row.to"
|
||||
class="vn-mb-sm">
|
||||
class="vn-mb-sm ellipsize">
|
||||
<span ng-if="row.to">
|
||||
{{::row.from | date:'dd/MM/yyyy'}} - {{::row.to | date:'dd/MM/yyyy'}}
|
||||
{{::row.from | date:'dd/MM/yy'}} - {{::row.to | date:'dd/MM/yy'}}
|
||||
</span>
|
||||
<span ng-if="!row.to" translate>
|
||||
Indefinitely
|
||||
|
@ -51,21 +84,13 @@
|
|||
<vn-icon-button
|
||||
icon="delete"
|
||||
translate-attr="{title: 'Delete'}"
|
||||
ng-click="$ctrl.onDelete(row.id, $event)">
|
||||
ng-click="$ctrl.onDeleteClick(row.id, $event)">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
</vn-horizontal>
|
||||
</a>
|
||||
</div>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
</div>
|
||||
<vn-side-menu side="right">
|
||||
<vn-zone-calendar
|
||||
events="data"
|
||||
exclusions="exclusions"
|
||||
on-selection="$ctrl.onCreate($days, $type, $weekday)">
|
||||
</vn-zone-calendar>
|
||||
</vn-side-menu>
|
||||
<vn-dialog
|
||||
vn-id="dialog"
|
||||
|
@ -89,16 +114,10 @@
|
|||
val="range">
|
||||
</vn-radio>
|
||||
</vn-vertical>
|
||||
<div
|
||||
<vn-wday-picker
|
||||
ng-if="$ctrl.eventType != 'day'"
|
||||
class="week-days">
|
||||
<span
|
||||
ng-repeat="wday in $ctrl.wdays"
|
||||
ng-class="{marked: $ctrl.selected.wdays[wday.code]}"
|
||||
ng-click="$ctrl.selected.wdays[wday.code] = !$ctrl.selected.wdays[wday.code]">
|
||||
{{wday.abr}}
|
||||
</span>
|
||||
</div>
|
||||
ng-model="$ctrl.selected.wdays">
|
||||
</vn-wday-picker>
|
||||
<vn-date-picker
|
||||
ng-if="$ctrl.eventType == 'day'"
|
||||
label="Day"
|
||||
|
@ -140,8 +159,21 @@
|
|||
</vn-vertical>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="ACCEPT" translate>Save</button>
|
||||
<input
|
||||
type="button"
|
||||
response="CANCEL"
|
||||
translate-attr="{value: 'Cancel'}">
|
||||
</input>
|
||||
<button
|
||||
ng-if="!$ctrl.isNew"
|
||||
response="DELETE"
|
||||
translate>
|
||||
Delete
|
||||
</button>
|
||||
<button response="ACCEPT">
|
||||
<span ng-if="$ctrl.isNew" translate>Add</span>
|
||||
<span ng-if="!$ctrl.isNew" translate>Save</span>
|
||||
</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
||||
<vn-confirm
|
||||
|
|
|
@ -1,53 +1,28 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'core/lib/section';
|
||||
import './style.scss';
|
||||
|
||||
class Controller extends Section {
|
||||
constructor($el, $, $t, $http, $state) {
|
||||
constructor($el, $, $t, $http, $state, $q, vnWeekDays) {
|
||||
super($el, $, $t, $http, $state);
|
||||
this.$q = $q;
|
||||
this.vnWeekDays = vnWeekDays;
|
||||
this.editMode = 'include';
|
||||
|
||||
this.wdays = [
|
||||
{
|
||||
code: 'mon',
|
||||
name: 'Monday'
|
||||
}, {
|
||||
code: 'tue',
|
||||
name: 'Tuesday'
|
||||
}, {
|
||||
code: 'wed',
|
||||
name: 'Wednesday'
|
||||
}, {
|
||||
code: 'thu',
|
||||
name: 'Thursday'
|
||||
}, {
|
||||
code: 'fri',
|
||||
name: 'Friday'
|
||||
}, {
|
||||
code: 'sat',
|
||||
name: 'Saturday'
|
||||
}, {
|
||||
code: 'sun',
|
||||
name: 'Sunday'
|
||||
}
|
||||
];
|
||||
|
||||
this.abrWdays = {};
|
||||
for (let wday of this.wdays) {
|
||||
let locale = this._(wday.name);
|
||||
this.abrWdays[wday.code] = locale.substr(0, 3);
|
||||
wday.abr = locale.substr(0, 1);
|
||||
}
|
||||
|
||||
this.$http.get(`/api/Zones/${this.$stateParams.id}/exclusions`)
|
||||
.then(res => this.$.exclusions = res.data);
|
||||
|
||||
this.path = `/api/Zones/${this.$stateParams.id}/events`;
|
||||
this.path = `api/Zones/${this.$stateParams.id}/events`;
|
||||
this.exclusionsPath = `api/Zones/${this.$stateParams.id}/exclusions`;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
let data = {};
|
||||
this.$q.all([
|
||||
this.$http.get(this.path)
|
||||
.then(res => this.$.data = res.data);
|
||||
.then(res => data.events = res.data),
|
||||
this.$http.get(this.exclusionsPath)
|
||||
.then(res => data.exclusions = res.data)
|
||||
]).finally(() => {
|
||||
this.$.data = data;
|
||||
});
|
||||
}
|
||||
|
||||
formatWdays(weekDays) {
|
||||
|
@ -55,16 +30,43 @@ class Controller extends Section {
|
|||
|
||||
let abrWdays = [];
|
||||
for (let wday of weekDays.split(','))
|
||||
abrWdays.push(this.abrWdays[wday]);
|
||||
abrWdays.push(this.vnWeekDays.map[wday].localeAbr);
|
||||
|
||||
return abrWdays.length < 7
|
||||
? abrWdays.join(', ')
|
||||
: this._('Everyday');
|
||||
}
|
||||
|
||||
onEdit(row, event) {
|
||||
if (event.defaultPrevented) return;
|
||||
onSelection(days, type, weekday, data) {
|
||||
if (this.editMode == 'include') {
|
||||
let dayData = data[0] || {};
|
||||
let event = dayData.events && dayData.events[0];
|
||||
|
||||
if (event)
|
||||
this.edit(event);
|
||||
else
|
||||
this.create(days, type, weekday);
|
||||
} else {
|
||||
let exclusions = [];
|
||||
for (let dayData of data) {
|
||||
if (dayData.exclusion)
|
||||
exclusions.push(dayData.exclusion.id);
|
||||
}
|
||||
|
||||
if (exclusions.length)
|
||||
this.exclusionDelete(exclusions);
|
||||
else
|
||||
this.exclusionCreate(days);
|
||||
}
|
||||
}
|
||||
|
||||
onEditClick(row, event) {
|
||||
if (event.defaultPrevented) return;
|
||||
event.preventDefault();
|
||||
this.edit(row);
|
||||
}
|
||||
|
||||
edit(row) {
|
||||
this.isNew = false;
|
||||
|
||||
if (row.from && !row.to)
|
||||
|
@ -86,25 +88,23 @@ class Controller extends Section {
|
|||
this.$.dialog.show();
|
||||
}
|
||||
|
||||
onCreate($day, $type, $weekday) {
|
||||
create(days, type, weekday) {
|
||||
this.isNew = true;
|
||||
this.eventType = $type == 'day' ? 'day' : 'indefinitely';
|
||||
this.eventType = type == 'day' ? 'day' : 'indefinitely';
|
||||
|
||||
if ($type == 'weekday') {
|
||||
if (type == 'weekday') {
|
||||
let wdays = [];
|
||||
let index = $weekday - 1;
|
||||
if (index < 0) index = 7 - index;
|
||||
wdays[this.wdays[index].code] = true;
|
||||
let code = this.vnWeekDays.days[weekday].code;
|
||||
wdays[code] = true;
|
||||
this.selected = {wdays};
|
||||
} else
|
||||
this.selected = {from: $day[0]};
|
||||
this.selected = {from: days[0]};
|
||||
|
||||
this.$.dialog.show();
|
||||
}
|
||||
|
||||
onSave(response) {
|
||||
if (response != 'ACCEPT') return;
|
||||
|
||||
if (response == 'ACCEPT') {
|
||||
let selected = this.selected;
|
||||
|
||||
if (this.eventType == 'indefinitely') {
|
||||
|
@ -141,12 +141,21 @@ class Controller extends Section {
|
|||
});
|
||||
|
||||
return false;
|
||||
} else if (response == 'DELETE') {
|
||||
this.onDelete(this.selected.id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
onDelete(id, event) {
|
||||
onDeleteClick(id, event) {
|
||||
if (event.defaultPrevented) return;
|
||||
event.preventDefault();
|
||||
this.$.confirm.show();
|
||||
this.onDelete(id);
|
||||
}
|
||||
|
||||
onDelete(id) {
|
||||
this.deleteId = id;
|
||||
this.$.confirm.show();
|
||||
}
|
||||
|
||||
delete(response) {
|
||||
|
@ -156,10 +165,34 @@ class Controller extends Section {
|
|||
.then(() => {
|
||||
this.refresh();
|
||||
this.deleteId = null;
|
||||
this.$.dialog.hide();
|
||||
});
|
||||
}
|
||||
|
||||
exclusionCreate(days) {
|
||||
let exclusions = days.map(day => {
|
||||
return {day};
|
||||
});
|
||||
|
||||
this.$http.post(this.exclusionsPath, exclusions)
|
||||
.then(() => this.refresh());
|
||||
}
|
||||
|
||||
exclusionDelete(ids) {
|
||||
let promises = [];
|
||||
|
||||
for (let id of ids) {
|
||||
promises.push(
|
||||
this.$http.delete(`${this.exclusionsPath}/${id}`)
|
||||
);
|
||||
}
|
||||
|
||||
this.$q.all(promises)
|
||||
.then(() => this.refresh());
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope', '$translate', '$http', '$state', '$q', 'vnWeekDays'];
|
||||
|
||||
ngModule.component('vnZoneEvents', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Edit mode: Modo de edición
|
||||
Include: Incluir
|
||||
Exclude: Excluir
|
||||
Events: Eventos
|
|
@ -1,28 +0,0 @@
|
|||
@import "effects";
|
||||
|
||||
vn-zone-events {
|
||||
.week-days {
|
||||
margin-top: $spacing-sm;
|
||||
margin-bottom: $spacing-md;
|
||||
text-align: center;
|
||||
|
||||
& > span {
|
||||
@extend %clickable;
|
||||
border-radius: 50%;
|
||||
padding: .4em;
|
||||
margin: .2em;
|
||||
display: inline-flex;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
background-color: rgba(0, 0, 0, .05);
|
||||
|
||||
&.marked {
|
||||
background: $color-main;
|
||||
color: $color-font-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<div class="main-with-right-menu">
|
||||
<vn-data-viewer
|
||||
data="data"
|
||||
is-loading="!data"
|
||||
class="vn-w-xs">
|
||||
<vn-card>
|
||||
<vn-table>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="row in data | orderBy:'day'">
|
||||
<vn-td>{{::row.day | date:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
icon="delete"
|
||||
translate-attr="{title: 'Delete'}"
|
||||
ng-click="$ctrl.onDelete(row.id)">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
</div>
|
||||
<vn-side-menu side="right">
|
||||
<vn-zone-calendar
|
||||
events="events"
|
||||
exclusions="data"
|
||||
on-selection="$ctrl.onCreate($days)">
|
||||
</vn-zone-calendar>
|
||||
</vn-side-menu>
|
|
@ -1,35 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'core/lib/section';
|
||||
|
||||
class Controller extends Section {
|
||||
constructor($el, $, $t, $http, $state) {
|
||||
super($el, $, $t, $http, $state);
|
||||
|
||||
this.$http.get(`/api/Zones/${this.$stateParams.id}/events`)
|
||||
.then(res => this.$.events = res.data);
|
||||
|
||||
this.path = `/api/Zones/${this.$stateParams.id}/exclusions`;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.$http.get(this.path)
|
||||
.then(res => this.$.data = res.data);
|
||||
}
|
||||
|
||||
onCreate($days) {
|
||||
this.$http.post(this.path, {day: $days[0]})
|
||||
.then(() => this.refresh());
|
||||
}
|
||||
|
||||
onDelete(id) {
|
||||
if (!id) return;
|
||||
this.$http.delete(`${this.path}/${id}`)
|
||||
.then(() => this.refresh());
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnZoneExclusions', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -12,6 +12,5 @@ import './basic-data';
|
|||
import './warehouses';
|
||||
import './events';
|
||||
import './calendar';
|
||||
import './exclusions';
|
||||
import './location';
|
||||
import './calendar';
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
{"state": "zone.card.basicData", "icon": "settings"},
|
||||
{"state": "zone.card.location", "icon": "my_location"},
|
||||
{"state": "zone.card.warehouses", "icon": "home"},
|
||||
{"state": "zone.card.events", "icon": "today"},
|
||||
{"state": "zone.card.exclusions", "icon": "block"}
|
||||
{"state": "zone.card.events", "icon": "today"}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
@ -65,11 +64,6 @@
|
|||
"state": "zone.card.events",
|
||||
"component": "vn-zone-events",
|
||||
"description": "Calendar"
|
||||
}, {
|
||||
"url": "/exclusions",
|
||||
"state": "zone.card.exclusions",
|
||||
"component": "vn-zone-exclusions",
|
||||
"description": "Exclusions"
|
||||
}, {
|
||||
"url": "/location?q",
|
||||
"state": "zone.card.location",
|
||||
|
|
|
@ -1,36 +1,39 @@
|
|||
<vn-crud-model
|
||||
url="/api/AbsenceTypes"
|
||||
data="$ctrl.absenceTypes" auto-load="true">
|
||||
url="api/AbsenceTypes"
|
||||
data="absenceTypes"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<div class="main-with-right-menu">
|
||||
<vn-card class="vn-pa-sm">
|
||||
<vn-horizontal class="calendar-list">
|
||||
<section class="calendar" ng-repeat="month in $ctrl.months">
|
||||
<div>
|
||||
<vn-card class="vn-pa-sm vn-w-xl calendars">
|
||||
<vn-calendar
|
||||
ng-repeat="month in $ctrl.months"
|
||||
data="$ctrl.events"
|
||||
default-date="month"
|
||||
display-controls="false">
|
||||
format-day="$ctrl.formatDay($day, $element)"
|
||||
display-controls="false"
|
||||
hide-contiguous="true"
|
||||
hide-year="true">
|
||||
</vn-calendar>
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
</div>
|
||||
</div>
|
||||
<vn-side-menu side="right">
|
||||
<vn-vertical class="vn-pa-sm">
|
||||
<vn-vertical class="totalBox">
|
||||
<div class="vn-pa-md">
|
||||
<div class="totalBox" style="text-align: center;">
|
||||
<h6 translate>Holidays</h6>
|
||||
<vn-auto>
|
||||
<div>
|
||||
{{'Used' | translate}} {{$ctrl.calendar.holidaysEnjoyed}}
|
||||
{{'of' | translate}} {{$ctrl.calendar.totalHolidays}} {{'days' | translate}}
|
||||
</vn-auto>
|
||||
</vn-vertical>
|
||||
<div>
|
||||
<vn-chip ng-repeat="legend in $ctrl.legends">
|
||||
</div>
|
||||
</div>
|
||||
<div class="vn-pt-md">
|
||||
<vn-chip ng-repeat="absenceType in absenceTypes">
|
||||
<vn-avatar
|
||||
ng-style="{backgroundColor: legend.color}">
|
||||
ng-style="{backgroundColor: absenceType.rgb}">
|
||||
</vn-avatar>
|
||||
{{legend.name}}
|
||||
{{absenceType.name}}
|
||||
</vn-chip>
|
||||
</div>
|
||||
</vn-vertical>
|
||||
</vn-side-menu>
|
||||
</div>
|
||||
</vn-side-menu>
|
|
@ -2,11 +2,39 @@ import ngModule from '../module';
|
|||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http) {
|
||||
this.$scope = $scope;
|
||||
constructor($element, $http) {
|
||||
this.element = $element[0];
|
||||
this.$http = $http;
|
||||
this.months = this.monthsOfYear();
|
||||
this.events = [];
|
||||
this.date = new Date();
|
||||
this.events = {};
|
||||
}
|
||||
|
||||
get date() {
|
||||
return this._date;
|
||||
}
|
||||
|
||||
set date(value) {
|
||||
this._date = value;
|
||||
value.setHours(0, 0, 0, 0);
|
||||
|
||||
const started = new Date(value.getTime());
|
||||
started.setMonth(0);
|
||||
started.setDate(1);
|
||||
this.started = started;
|
||||
|
||||
const ended = new Date(value.getTime());
|
||||
ended.setMonth(12);
|
||||
ended.setDate(0);
|
||||
this.ended = ended;
|
||||
|
||||
this.months = new Array(12);
|
||||
|
||||
for (let i = 0; i < this.months.length; i++) {
|
||||
const now = new Date(value.getTime());
|
||||
now.setDate(1);
|
||||
now.setMonth(i);
|
||||
this.months[i] = now;
|
||||
}
|
||||
}
|
||||
|
||||
get worker() {
|
||||
|
@ -15,118 +43,67 @@ class Controller {
|
|||
|
||||
set worker(value) {
|
||||
this._worker = value;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
let params = {params: {
|
||||
let params = {
|
||||
workerFk: this.worker.id,
|
||||
started: this.started,
|
||||
ended: this.ended
|
||||
}};
|
||||
|
||||
let query = `/worker/api/WorkerCalendars/absences`;
|
||||
this.$http.get(query, params).then(res => {
|
||||
if (!res.data) return;
|
||||
|
||||
this.setHolidays(res.data);
|
||||
this.setWorkerCalendar(res.data);
|
||||
this.calendar = res.data.calendar;
|
||||
});
|
||||
};
|
||||
this.$http.get(`api/WorkerCalendars/absences`, {params})
|
||||
.then(res => this.onData(res.data));
|
||||
}
|
||||
|
||||
setHolidays(data) {
|
||||
if (!data.holidays) return;
|
||||
onData(data) {
|
||||
this.events = {};
|
||||
this.calendar = data.calendar;
|
||||
|
||||
const holidays = data.holidays;
|
||||
const events = [];
|
||||
holidays.forEach(holiday => {
|
||||
let addEvent = (day, event) => {
|
||||
this.events[new Date(day).getTime()] = event;
|
||||
};
|
||||
|
||||
if (data.holidays) {
|
||||
data.holidays.forEach(holiday => {
|
||||
const holidayDetail = holiday.detail && holiday.detail.description;
|
||||
const holidayType = holiday.type && holiday.type.name;
|
||||
const holidayName = holidayDetail || holidayType;
|
||||
|
||||
events.push({
|
||||
addEvent(holiday.dated, {
|
||||
name: holidayName,
|
||||
description: holidayName,
|
||||
dated: holiday.dated,
|
||||
isRemovable: false,
|
||||
style: {backgroundColor: '#FFFF00'}
|
||||
color: '#ff0'
|
||||
});
|
||||
});
|
||||
this.events = this.events.concat(events);
|
||||
}
|
||||
|
||||
setWorkerCalendar(data) {
|
||||
if (!data.absences) return;
|
||||
|
||||
const absences = data.absences;
|
||||
const events = [];
|
||||
absences.forEach(absence => {
|
||||
const absenceType = absence.absenceType;
|
||||
events.push({
|
||||
name: absenceType.name,
|
||||
description: absenceType.name,
|
||||
dated: absence.dated,
|
||||
style: {backgroundColor: absenceType.rgb}
|
||||
if (data.absences) {
|
||||
data.absences.forEach(absence => {
|
||||
let type = absence.absenceType;
|
||||
addEvent(absence.dated, {
|
||||
name: type.name,
|
||||
color: type.rgb
|
||||
});
|
||||
});
|
||||
this.events = this.events.concat(events);
|
||||
}
|
||||
|
||||
get started() {
|
||||
const started = new Date();
|
||||
started.setHours(0, 0, 0, 0);
|
||||
started.setMonth(0);
|
||||
started.setDate(1);
|
||||
|
||||
return started;
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
get ended() {
|
||||
const monthIndex = 11;
|
||||
const ended = new Date();
|
||||
ended.setHours(0, 0, 0, 0);
|
||||
ended.setMonth(monthIndex + 1);
|
||||
// Last day of previous month (January)
|
||||
ended.setDate(0);
|
||||
|
||||
return ended;
|
||||
repaint() {
|
||||
let calendars = this.element.querySelectorAll('vn-calendar');
|
||||
for (let calendar of calendars)
|
||||
calendar.$ctrl.repaint();
|
||||
}
|
||||
|
||||
monthsOfYear() {
|
||||
let months = new Array(12);
|
||||
formatDay(day, element) {
|
||||
let event = this.events[day.getTime()];
|
||||
if (!event) return;
|
||||
|
||||
for (let i = 0; i < months.length; i++) {
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
now.setDate(1);
|
||||
now.setMonth(i);
|
||||
|
||||
months[i] = now;
|
||||
}
|
||||
|
||||
return months;
|
||||
}
|
||||
|
||||
get absenceTypes() {
|
||||
return this._absenceTypes;
|
||||
}
|
||||
|
||||
set absenceTypes(value) {
|
||||
if (value) {
|
||||
this._absenceTypes = value;
|
||||
this.legends = [];
|
||||
this._absenceTypes.forEach(absenceType => {
|
||||
let legend = {};
|
||||
legend.id = absenceType.id;
|
||||
legend.color = absenceType.rgb;
|
||||
legend.name = absenceType.name;
|
||||
this.legends.push(legend);
|
||||
});
|
||||
let dayNumber = element.firstElementChild;
|
||||
dayNumber.title = event.name;
|
||||
dayNumber.style.backgroundColor = event.color;
|
||||
dayNumber.style.color = 'white';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http'];
|
||||
Controller.$inject = ['$element', '$http'];
|
||||
|
||||
ngModule.component('vnWorkerCalendar', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -2,147 +2,111 @@ import './index';
|
|||
|
||||
describe('Worker', () => {
|
||||
describe('Component vnWorkerCalendar', () => {
|
||||
let $componentController;
|
||||
let $httpParamSerializer;
|
||||
let $httpBackend;
|
||||
let $scope;
|
||||
let $element;
|
||||
let controller;
|
||||
let year = new Date().getFullYear();
|
||||
|
||||
beforeEach(angular.mock.module('worker', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$componentController = _$componentController_;
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
controller = $componentController('vnWorkerCalendar', {$scope, $httpBackend});
|
||||
$element = angular.element('<div></div>');
|
||||
controller = $componentController('vnWorkerCalendar', {$element, $scope});
|
||||
}));
|
||||
|
||||
describe('started() getter', () => {
|
||||
it(`should return first day and month of current year`, () => {
|
||||
let started = new Date();
|
||||
started.setHours(0, 0, 0, 0);
|
||||
started.setMonth(0);
|
||||
started.setDate(1);
|
||||
afterEach(() => {
|
||||
$element.remove();
|
||||
$scope.$destroy();
|
||||
});
|
||||
|
||||
describe('started property', () => {
|
||||
it(`should return first day and month of current year`, () => {
|
||||
let started = new Date(year, 0, 1);
|
||||
|
||||
expect(controller.started).toEqual(started);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ended() getter', () => {
|
||||
describe('ended property', () => {
|
||||
it(`should return last day and month of current year`, () => {
|
||||
const monthIndex = 11;
|
||||
const ended = new Date();
|
||||
ended.setHours(0, 0, 0, 0);
|
||||
ended.setMonth(monthIndex + 1);
|
||||
// Last day of previous month (January)
|
||||
ended.setDate(0);
|
||||
let ended = new Date(year, 11, 31);
|
||||
|
||||
expect(controller.ended).toEqual(ended);
|
||||
});
|
||||
});
|
||||
|
||||
describe('monthsOfYear()', () => {
|
||||
describe('months property', () => {
|
||||
it(`should return an array of twelve months length`, () => {
|
||||
const months = controller.monthsOfYear();
|
||||
const ended = new Date();
|
||||
ended.setHours(0, 0, 0, 0);
|
||||
ended.setMonth(11);
|
||||
ended.setDate(1);
|
||||
const ended = new Date(year, 11, 1);
|
||||
|
||||
expect(months.length).toEqual(12);
|
||||
expect(months[0]).toEqual(controller.started);
|
||||
expect(months[11]).toEqual(ended);
|
||||
expect(controller.months.length).toEqual(12);
|
||||
expect(controller.months[0]).toEqual(controller.started);
|
||||
expect(controller.months[11]).toEqual(ended);
|
||||
});
|
||||
});
|
||||
|
||||
describe('worker() setter', () => {
|
||||
it(`should perform a get query and call setHolidays() and setWorkerCalendar() methods`, () => {
|
||||
const worker = {id: 106};
|
||||
spyOn(controller, 'setHolidays');
|
||||
spyOn(controller, 'setWorkerCalendar');
|
||||
it(`should perform a get query and set the reponse data on the model`, () => {
|
||||
let today = new Date();
|
||||
|
||||
const expectedData = {
|
||||
calendar: {},
|
||||
absences: {}
|
||||
};
|
||||
let params = $httpParamSerializer({
|
||||
workerFk: worker.id,
|
||||
started: controller.started,
|
||||
ended: controller.ended
|
||||
let tomorrow = new Date(today.getTime());
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
let yesterday = new Date(today.getTime());
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
let path = `api/WorkerCalendars/absences`;
|
||||
$httpBackend.whenGET(url => url.startsWith(path))
|
||||
.respond({
|
||||
holidays: [
|
||||
{dated: today, detail: {description: 'New year'}},
|
||||
{dated: tomorrow, detail: {description: 'Easter'}}
|
||||
],
|
||||
absences: [
|
||||
{dated: today, absenceType: {name: 'Holiday', rgb: '#aaa'}},
|
||||
{dated: yesterday, absenceType: {name: 'Leave', rgb: '#bbb'}}
|
||||
]
|
||||
});
|
||||
$httpBackend.when('GET', `/worker/api/WorkerCalendars/absences?${params}`).respond(expectedData);
|
||||
$httpBackend.expect('GET', `/worker/api/WorkerCalendars/absences?${params}`);
|
||||
|
||||
controller.worker = worker;
|
||||
|
||||
controller.worker = {id: 1};
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.setHolidays).toHaveBeenCalledWith(expectedData);
|
||||
expect(controller.setHolidays).toHaveBeenCalledWith(expectedData);
|
||||
let events = controller.events;
|
||||
|
||||
expect(events[today.getTime()].name).toEqual('Holiday');
|
||||
expect(events[tomorrow.getTime()].name).toEqual('Easter');
|
||||
expect(events[yesterday.getTime()].name).toEqual('Leave');
|
||||
expect(events[yesterday.getTime()].color).toEqual('#bbb');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setHolidays()', () => {
|
||||
it(`should set holidays`, () => {
|
||||
const data = {holidays: [
|
||||
{dated: new Date(), detail: {description: 'New year'}},
|
||||
{dated: new Date(), detail: {description: 'Easter'}}
|
||||
]};
|
||||
controller.setHolidays(data);
|
||||
describe('formatDay()', () => {
|
||||
it(`should set the day element style`, () => {
|
||||
let today = new Date();
|
||||
|
||||
expect(controller.events.length).toEqual(2);
|
||||
expect(controller.events[0].name).toEqual('New year');
|
||||
expect(controller.events[0].isRemovable).toEqual(false);
|
||||
});
|
||||
let path = `api/WorkerCalendars/absences`;
|
||||
$httpBackend.whenGET(url => url.startsWith(path))
|
||||
.respond({
|
||||
absences: [
|
||||
{dated: today, absenceType: {name: 'Holiday', rgb: '#000'}}
|
||||
]
|
||||
});
|
||||
|
||||
describe('setWorkerCalendar()', () => {
|
||||
it(`should set absences of differente types`, () => {
|
||||
const data = {absences: [
|
||||
{dated: new Date(), absenceType: {name: 'Holiday', rgb: '#000'}},
|
||||
{dated: new Date(), absenceType: {name: 'Leave', rgb: '#000'}}
|
||||
]};
|
||||
controller.setWorkerCalendar(data);
|
||||
controller.worker = {id: 1};
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.events.length).toEqual(2);
|
||||
expect(controller.events[0].name).toEqual('Holiday');
|
||||
expect(controller.events[0].style).toBeDefined();
|
||||
expect(controller.events[1].name).toEqual('Leave');
|
||||
expect(controller.events[1].style).toBeDefined();
|
||||
});
|
||||
});
|
||||
let dayElement = angular.element('<div><section></section></div>')[0];
|
||||
let dayNumber = dayElement.firstElementChild;
|
||||
|
||||
describe('absenceTypes() setter', () => {
|
||||
it(`should set the absence types in the controller`, () => {
|
||||
const absenceTypes = [
|
||||
{id: 1, name: 'Holiday', rgb: '#000'},
|
||||
{id: 2, name: 'Leave', rgb: '#000'}
|
||||
];
|
||||
controller.formatDay(today, dayElement);
|
||||
|
||||
expect(controller._absenceTypes).not.toBeDefined();
|
||||
|
||||
controller.absenceTypes = absenceTypes;
|
||||
|
||||
expect(controller._absenceTypes.length).toEqual(2);
|
||||
});
|
||||
|
||||
it(`should set the absence types in the controller as formated legends`, () => {
|
||||
const absenceTypes = [
|
||||
{id: 1, name: 'Holiday', rgb: '#000'},
|
||||
{id: 2, name: 'Leave', rgb: '#000'}
|
||||
];
|
||||
|
||||
expect(controller.legends).not.toBeDefined();
|
||||
|
||||
controller.absenceTypes = absenceTypes;
|
||||
|
||||
expect(controller.legends.length).toEqual(2);
|
||||
expect(controller.legends[0].color).toBeDefined();
|
||||
expect(controller.legends[1].color).toBeDefined();
|
||||
expect(dayNumber.title).toEqual('Holiday');
|
||||
expect(dayNumber.style.backgroundColor).toEqual('rgb(0, 0, 0)');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,34 +1,19 @@
|
|||
@import "variables";
|
||||
|
||||
|
||||
/* .calendar-list .calendar:nth-child(2n + 1) {
|
||||
border-right:1px solid #ddd
|
||||
} */
|
||||
|
||||
.calendar-list {
|
||||
align-items: flex-start;
|
||||
vn-worker-calendar {
|
||||
.calendars {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
.calendar {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: $spacing-md;
|
||||
overflow: hidden;
|
||||
min-width: 18em;
|
||||
width: 25%;
|
||||
|
||||
vn-calendar {
|
||||
& > vn-calendar {
|
||||
border: 1px solid #ddd;
|
||||
padding: 0.5em
|
||||
margin: $spacing-md;
|
||||
padding: $spacing-xs;
|
||||
max-width: 18em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vn-horizontal.header {
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
.totalBox {
|
||||
max-width: 15em
|
||||
}
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/worker/api/WorkerTimeControls/filter"
|
||||
url="api/WorkerTimeControls/filter"
|
||||
filter="::$ctrl.filter"
|
||||
data="$ctrl.hours">
|
||||
</vn-crud-model>
|
||||
<div class="main-with-right-menu">
|
||||
<vn-card class="compact vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-table model="model" auto-load="false" vn-one>
|
||||
<vn-card class="vn-pa-lg vn-w-md">
|
||||
<vn-table model="model" auto-load="false">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-td ng-repeat="weekday in $ctrl.weekDays" center>
|
||||
|
@ -34,13 +33,14 @@
|
|||
</vn-tbody>
|
||||
<vn-tfoot>
|
||||
<vn-tr>
|
||||
<vn-td center ng-repeat="weekday in $ctrl.weekDays">
|
||||
<vn-td ng-repeat="weekday in $ctrl.weekDays" center>
|
||||
{{$ctrl.getWeekdayTotalHours(weekday)}} h.
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
<vn-tr>
|
||||
<vn-td center ng-repeat="weekday in $ctrl.weekDays">
|
||||
<vn-icon-button icon="add_circle"
|
||||
<vn-icon-button
|
||||
icon="add_circle"
|
||||
vn-tooltip="Add time"
|
||||
ng-click="$ctrl.showAddTimeDialog(weekday)">
|
||||
</vn-icon-button>
|
||||
|
@ -48,29 +48,26 @@
|
|||
</vn-tr>
|
||||
</vn-tfoot>
|
||||
</vn-table>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-side-menu side="right">
|
||||
<vn-vertical class="vn-pa-sm">
|
||||
<vn-vertical class="totalBox">
|
||||
<div class="vn-pa-md">
|
||||
<div class="totalBox" style="text-align: center;">
|
||||
<h6 translate>Hours</h6>
|
||||
<vn-label-value
|
||||
label="Week total"
|
||||
value="{{$ctrl.weekTotalHours}} {{'Hours' | translate}}">
|
||||
value="{{$ctrl.weekTotalHours}} h.">
|
||||
</vn-label-value>
|
||||
</vn-vertical>
|
||||
</vn-vertical>
|
||||
<vn-calendar class="vn-pa-sm"
|
||||
data="$ctrl.currentWeek"
|
||||
default-date="$ctrl.defaultDate"
|
||||
on-selection="$ctrl.onSelection($days)"
|
||||
on-move-next="$ctrl.onMoveNext()"
|
||||
on-move-previous="$ctrl.onMovePrevious()">
|
||||
</div>
|
||||
<vn-calendar
|
||||
class="vn-pt-md"
|
||||
ng-model="$ctrl.date"
|
||||
has-events="$ctrl.hasEvents($day)">
|
||||
</vn-calendar>
|
||||
</div>
|
||||
</vn-side-menu>
|
||||
</div>
|
||||
|
||||
<vn-dialog vn-id="addTimeDialog"
|
||||
<vn-dialog
|
||||
vn-id="addTimeDialog"
|
||||
on-response="$ctrl.addTime(response)">
|
||||
<tpl-body>
|
||||
<div>
|
||||
|
|
|
@ -2,155 +2,91 @@ import ngModule from '../module';
|
|||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http, $stateParams, $element) {
|
||||
constructor($scope, $http, $stateParams, $element, vnWeekDays) {
|
||||
this.$stateParams = $stateParams;
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.$element = $element;
|
||||
this.defaultDate = new Date();
|
||||
this.currentWeek = [];
|
||||
this.weekDays = [];
|
||||
this.weekdayNames = [
|
||||
{name: 'Monday'},
|
||||
{name: 'Tuesday'},
|
||||
{name: 'Wednesday'},
|
||||
{name: 'Thursday'},
|
||||
{name: 'Friday'},
|
||||
{name: 'Saturday'},
|
||||
{name: 'Sunday'}
|
||||
];
|
||||
this.weekdayNames = vnWeekDays.locales;
|
||||
}
|
||||
|
||||
$postLink() {
|
||||
this.date = new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets worker data
|
||||
* The current selected date
|
||||
*/
|
||||
get worker() {
|
||||
return this._worker;
|
||||
get date() {
|
||||
return this._date;
|
||||
}
|
||||
|
||||
set date(value) {
|
||||
this._date = value;
|
||||
value.setHours(0, 0, 0, 0);
|
||||
|
||||
let weekOffset = value.getDay() - 1;
|
||||
if (weekOffset < 0) weekOffset = 6;
|
||||
|
||||
let started = new Date(value.getTime());
|
||||
started.setDate(started.getDate() - weekOffset);
|
||||
this.started = started;
|
||||
|
||||
let ended = new Date(started.getTime());
|
||||
ended.setDate(ended.getDate() + 7);
|
||||
this.ended = ended;
|
||||
|
||||
this.fetchHours();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets worker data and retrieves
|
||||
* worker hours
|
||||
*
|
||||
* @param {Object} value - Worker data
|
||||
*/
|
||||
set worker(value) {
|
||||
this._worker = value;
|
||||
|
||||
if (value) {
|
||||
this.$.$applyAsync(() => {
|
||||
this.getHours();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets worker hours data
|
||||
*
|
||||
* Worker hours data
|
||||
*/
|
||||
get hours() {
|
||||
return this._hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets worker hours data
|
||||
*
|
||||
* @param {Object} value - Hours data
|
||||
*/
|
||||
set hours(value) {
|
||||
this._hours = value;
|
||||
if (value) this.build();
|
||||
this.weekDays = [];
|
||||
if (!this.hours) return;
|
||||
|
||||
let dayIndex = new Date(this.started.getTime());
|
||||
|
||||
while (dayIndex < this.ended) {
|
||||
let weekDay = dayIndex.getDay();
|
||||
|
||||
let hours = this.hours
|
||||
.filter(hour => new Date(hour.timed).getDay() == weekDay)
|
||||
.sort((a, b) => new Date(a.timed) - new Date(b.timed));
|
||||
|
||||
this.weekDays.push({
|
||||
dated: new Date(dayIndex.getTime()),
|
||||
hours
|
||||
});
|
||||
dayIndex.setDate(dayIndex.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
getHours() {
|
||||
const params = {workerFk: this.worker.id};
|
||||
fetchHours() {
|
||||
const params = {workerFk: this.$stateParams.id};
|
||||
const filter = {
|
||||
where: {
|
||||
timed: {between: [this.started, this.ended]}
|
||||
}
|
||||
where: {and: [
|
||||
{timed: {gte: this.started}},
|
||||
{timed: {lt: this.ended}}
|
||||
]}
|
||||
};
|
||||
|
||||
return this.$.model.applyFilter(filter, params);
|
||||
this.$.model.applyFilter(filter, params);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.getHours().then(() => this.build());
|
||||
}
|
||||
|
||||
build() {
|
||||
let weekdays = new Array(7);
|
||||
const currentWeek = [];
|
||||
|
||||
for (let i = 0; i < weekdays.length; i++) {
|
||||
const dated = new Date();
|
||||
dated.setHours(23, 59, 0, 0);
|
||||
dated.setMonth(this.started.getMonth());
|
||||
dated.setDate(this.started.getDate() + i);
|
||||
|
||||
const hours = this.hours.filter(hour => {
|
||||
const timed = new Date(hour.timed);
|
||||
const weekDay = timed.getDay() == 0 ? 7 : timed.getDay();
|
||||
return weekDay == (i + 1);
|
||||
});
|
||||
|
||||
const sortedHours = hours.sort((a, b) => {
|
||||
return new Date(a.timed) - new Date(b.timed);
|
||||
});
|
||||
|
||||
weekdays[i] = {dated, hours: sortedHours};
|
||||
|
||||
currentWeek.push({
|
||||
dated: dated,
|
||||
className: 'orange-circle',
|
||||
title: 'Current week',
|
||||
isRemovable: false
|
||||
});
|
||||
}
|
||||
|
||||
this.currentWeek = currentWeek;
|
||||
this.weekDays = weekdays;
|
||||
hasEvents(day) {
|
||||
return day >= this.started && day < this.ended;
|
||||
}
|
||||
|
||||
hourColor(weekDay) {
|
||||
if (weekDay.manual)
|
||||
return 'alert';
|
||||
|
||||
return 'warning';
|
||||
}
|
||||
get weekOffset() {
|
||||
const timed = this.defaultDate;
|
||||
const weekDay = timed.getDay() == 0 ? 7 : timed.getDay();
|
||||
|
||||
return weekDay - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns week start date
|
||||
* from current selected week
|
||||
*/
|
||||
get started() {
|
||||
const started = new Date();
|
||||
const offset = this.weekOffset;
|
||||
|
||||
started.setMonth(this.defaultDate.getMonth());
|
||||
started.setDate(this.defaultDate.getDate() - offset);
|
||||
started.setHours(0, 0, 0, 0);
|
||||
|
||||
return started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns week end date
|
||||
* from current selected week
|
||||
*/
|
||||
get ended() {
|
||||
const ended = new Date();
|
||||
ended.setHours(0, 0, 0, 0);
|
||||
ended.setMonth(this.started.getMonth());
|
||||
ended.setDate(this.started.getDate() + 7);
|
||||
|
||||
return ended;
|
||||
return weekDay.manual ? 'alert' : 'warning';
|
||||
}
|
||||
|
||||
getWeekdayTotalHours(weekday) {
|
||||
|
@ -200,20 +136,6 @@ class Controller {
|
|||
return `${hour}:${min}`;
|
||||
}
|
||||
|
||||
onMoveNext() {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
onMovePrevious() {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
onSelection($days) {
|
||||
this.defaultDate.setMonth($days[0].getMonth());
|
||||
this.defaultDate.setDate($days[0].getDate());
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
showAddTimeDialog(weekday) {
|
||||
const timed = new Date(weekday.dated);
|
||||
const now = new Date();
|
||||
|
@ -226,26 +148,25 @@ class Controller {
|
|||
this.selectedWeekday = weekday;
|
||||
this.$.addTimeDialog.show();
|
||||
|
||||
const selector = 'vn-dialog[vn-id="addTimeDialog"] input[type="time"]';
|
||||
const selector = '[vn-id=addTimeDialog] input[type=time]';
|
||||
const input = this.$element[0].querySelector(selector);
|
||||
input.focus();
|
||||
}
|
||||
|
||||
addTime(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
let data = {workerFk: this.worker.id, timed: this.newTime};
|
||||
let query = `/api/WorkerTimeControls/addTime`;
|
||||
this.$http.post(query, data).then(() => this.refresh());
|
||||
}
|
||||
if (response !== 'ACCEPT') return;
|
||||
let data = {
|
||||
workerFk: this.$stateParams.id,
|
||||
timed: this.newTime
|
||||
};
|
||||
this.$http.post(`api/WorkerTimeControls/addTime`, data)
|
||||
.then(() => this.fetchHours());
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http', '$stateParams', '$element'];
|
||||
Controller.$inject = ['$scope', '$http', '$stateParams', '$element', 'vnWeekDays'];
|
||||
|
||||
ngModule.component('vnWorkerTimeControl', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
worker: '<'
|
||||
}
|
||||
controller: Controller
|
||||
});
|
||||
|
|
|
@ -2,37 +2,56 @@ import './index.js';
|
|||
|
||||
describe('Worker', () => {
|
||||
describe('Component vnWorkerTimeControl', () => {
|
||||
let $httpBackend;
|
||||
let $scope;
|
||||
let controller;
|
||||
let $element;
|
||||
let controller;
|
||||
|
||||
beforeEach(angular.mock.module('worker', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope) => {
|
||||
beforeEach(angular.mock.inject(($compile, $rootScope, $stateParams, _$httpBackend_) => {
|
||||
$stateParams.id = 1;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
$element = angular.element('<vn-worker-time-control></vn-worker-time-control>');
|
||||
controller = $componentController('vnWorkerTimeControl', {$scope, $element});
|
||||
$element = $compile('<vn-worker-time-control></vn-worker-time-control>')($scope);
|
||||
controller = $element.controller('vnWorkerTimeControl');
|
||||
}));
|
||||
|
||||
describe('worker() setter', () => {
|
||||
it(`should set worker data and then call getHours() method`, () => {
|
||||
spyOn(controller, 'getHours');
|
||||
controller.worker = {id: 106};
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.getHours).toHaveBeenCalledWith();
|
||||
});
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
$element.remove();
|
||||
});
|
||||
|
||||
describe('hours() setter', () => {
|
||||
it(`should set hours data and then call build() method`, () => {
|
||||
spyOn(controller, 'build');
|
||||
controller.hours = [{id: 1}, {id: 2}];
|
||||
$scope.$apply();
|
||||
it(`should set hours data at it's corresponding week day`, () => {
|
||||
let wednesday = new Date(controller.started.getTime());
|
||||
wednesday.setDate(wednesday.getDate() + 2);
|
||||
|
||||
expect(controller.build).toHaveBeenCalledWith();
|
||||
let path = `api/WorkerTimeControls/filter`;
|
||||
$httpBackend.whenGET(url => url.startsWith(path))
|
||||
.respond([
|
||||
{
|
||||
id: 1,
|
||||
timed: controller.started.toJSON(),
|
||||
userFk: 1
|
||||
}, {
|
||||
id: 2,
|
||||
timed: wednesday.toJSON(),
|
||||
userFk: 1
|
||||
}, {
|
||||
id: 3,
|
||||
timed: wednesday.toJSON(),
|
||||
userFk: 1
|
||||
}
|
||||
]);
|
||||
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.weekDays.length).toEqual(7);
|
||||
expect(controller.weekDays[0].hours.length).toEqual(1);
|
||||
expect(controller.weekDays[2].hours.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -3,5 +3,5 @@ Out: Salida
|
|||
Hour: Hora
|
||||
Hours: Horas
|
||||
Add time: Añadir hora
|
||||
Week total: Total por semana
|
||||
Week total: Total semana
|
||||
Current week: Semana actual
|
|
@ -5,23 +5,20 @@ vn-worker-time-control {
|
|||
margin-bottom: 5px;
|
||||
color: $color-main
|
||||
}
|
||||
|
||||
vn-td.hours {
|
||||
vertical-align: top;
|
||||
|
||||
& > section {
|
||||
position: relative;
|
||||
padding: .6em 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .3em 0;
|
||||
|
||||
& > vn-icon {
|
||||
position: absolute;
|
||||
margin-left: -1.3em;
|
||||
margin-top: -3px;
|
||||
color: $color-font-secondary;
|
||||
padding-right: .1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.totalBox {
|
||||
max-width: none
|
||||
}
|
||||
|
|
|
@ -103,6 +103,9 @@ let baseConfig = {
|
|||
favicon: 'front/salix/favicon.ico',
|
||||
filename: 'index.html',
|
||||
chunks: ['salix']
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
|
||||
})
|
||||
],
|
||||
devtool: 'source-map',
|
||||
|
|
Loading…
Reference in New Issue