Created
June 6, 2018 19:27
-
-
Save guilherme-teodoro/3578fe844b9f5bde1e64f87610501088 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns kitasato.components.vacation.index | |
(:require | |
[kitasato.components.box :as box] | |
[kitasato.components.card :as card] | |
[kitasato.components.container :as container] | |
[kitasato.components.dropdown :as dropdown] | |
[kitasato.components.grid :as grid] | |
[kitasato.components.icon :as icon] | |
[kitasato.components.scroll :as scroll] | |
[kitasato.components.spacing :as spacing] | |
[kitasato.components.spinner :as spinner] | |
[kitasato.components.table-kit :as table-kit] | |
[kitasato.components.tabs :as tabs] | |
[kitasato.components.typography :as typography] | |
[kitasato.components.vacation.common :as vacation-common] | |
[kitasato.components.vacation.form-modal :as individual-modal] | |
[kitasato.data.common :as common] | |
[kitasato.data.vacation :as vacation] | |
[kitasato.io.asset :as asset] | |
[kitasato.network.lukla :as lukla] | |
[kitasato.re-frame :refer [listen]] | |
[kitasato.router.path-helpers :as path-helpers] | |
[kitasato.storage.q :as q] | |
[kitasato.style.settings :as style] | |
[kitasato.time :as time] | |
[kitasato.ui.atoms.badge :as a-badge] | |
[kitasato.ui.atoms.buttons :as a-buttons] | |
[kitasato.ui.atoms.collapse :as a-collapse] | |
[kitasato.ui.atoms.layout :as a-layout] | |
[kitasato.ui.atoms.page :as a-page] | |
[kitasato.ui.molecules.mobile :as m-mobile] | |
[kitasato.ui.molecules.mobile.frame :as m-mobile-frame] | |
[kitasato.ui.molecules.user :as m-user] | |
[kitasato.ui.organisms.empty-state :as o-empty-state] | |
[kitasato.utils :as utils] | |
[reagent.core :as r])) | |
(defn- vacation-view-key | |
[vacation] | |
(let [date (vacation/attr->start_date vacation)] | |
[(time/year date) (time/month date)])) | |
(defn- same-month? | |
[a b] | |
(and (= (time/year a) (time/year b)) (= (time/month a) (time/month b)))) | |
(defn- gantt | |
[{:keys [vacations company-id loading? bounds timeframe on-timeframe-change on-select]}] | |
(let [now (time/now)] | |
[:div | |
[:div.Gantt | |
[:table.Gantt-profiles | |
[:thead [:tr [:th "Colaboradores"]]] | |
[:tbody | |
(doall | |
(for [vacation vacations] | |
^{:key (:id vacation)} | |
[:tr | |
[:td (m-user/avatar-name-position company-id (:id (vacation/->profile vacation)))]]))]] | |
[:div.Gantt-calendarWrapper | |
[:table.Gantt-calendar | |
[:thead | |
[:tr | |
[:th | |
[:button.Gantt-arrow.Gantt-arrow--left | |
{:disabled (or loading? | |
(when-let [min-date (:min bounds)] | |
(when-let [time (first timeframe)] | |
(> (time/timestamp min-date) (time/timestamp time))))), | |
:on-click (utils/maybe-handler on-timeframe-change -1)} | |
[icon/icon | |
{:icon "arrow", | |
:size "small"}]]] | |
(map (fn [time] | |
^{:key [(time/year time) (time/month time)]} | |
[:th | |
(time/abbreviated-months (time/month time)) | |
[:span.Gantt-calendar-year (subs (str (time/year time)) 2)]]) | |
timeframe) | |
[:th | |
[:button.Gantt-arrow | |
{:disabled (or loading? | |
(when-let [max-date (:max bounds)] | |
(when-let [time (last timeframe)] | |
(< (time/timestamp max-date) (time/timestamp time))))), | |
:on-click (utils/maybe-handler on-timeframe-change 1)} | |
[icon/icon | |
{:icon "arrow", | |
:size "small"}]]]]] | |
[:tbody | |
(doall | |
(for [vacation vacations] | |
(let [profile& (lukla/follow-1 vacation :profile)] | |
^{:key (:id vacation)} | |
[:tr | |
[:td ""] | |
(map (fn [timebase] | |
^{:key [(time/year timebase) (time/month timebase)]} | |
[:td | |
(when (same-month? timebase now) | |
(let [pad-now-line (str (* (/ (time/date now) (time/days-in-month now)) | |
100) | |
"%")] | |
[:span.Gantt-now {:style {:left pad-now-line}}])) | |
(when (same-month? timebase (vacation/attr->start_date vacation)) | |
(let [amount-in-days (vacation/attr->amount_in_days vacation) | |
start-date (vacation/attr->start_date vacation) | |
finish-date (vacation/attr->finish_date vacation) | |
pad-marker (str (* (/ (time/date start-date) 30) 100) "%") | |
pill-width (str (* (/ amount-in-days 30) 100) "%") | |
pad-pill-label (str (/ (* (- (/ amount-in-days | |
(time/days-in-month timebase)) | |
1) | |
100) | |
2) | |
"%")] | |
[:div.Gantt-marker | |
{:style {:left pad-marker}, | |
:on-click #(utils/maybe-call-fn on-select vacation)} | |
[:div.Gantt-pill | |
{:style {:width pill-width}, | |
:class (if (= (vacation/attr->status vacation) "approved") | |
"Gantt-pill--approved" | |
"Gantt-pill--pending")} | |
(str amount-in-days) | |
" dias"] | |
[:div.Gantt-pillLabel | |
{:style {:left pad-pill-label}} | |
(time/format start-date "DD/MM") | |
" → " | |
(time/format finish-date "DD/MM")]]))]) | |
timeframe) | |
[:td ""]])))]]]] | |
(when loading? | |
[:div | |
{:style {:display :flex, | |
:padding-top "25px", | |
:justify-content :center}} | |
[spinner/spinner | |
{:style {:width "25px", | |
:height "25px"}}]])])) | |
(defn- vacation-item | |
[{:keys [items date company-id profile-id]}] | |
[:div.Vacation-listItem | |
[:div | |
{:class "f6 ttu b"} | |
(time/months (get date 1)) | |
" " | |
[:span {:class "gray3"} (subs (str (get date 0)) 2)]] | |
(doall | |
(for [vacation items] | |
(let [profile& (lukla/follow-1 vacation :profile) | |
user& (lukla/follow-1 @profile& :user)] | |
^{:key (:id vacation)} | |
[:div | |
{:class "w-100 bb b--gray2 flex items-center pv3"} | |
(m-user/avatar-name company-id | |
(:id (vacation/->profile vacation)) | |
[:div | |
(time/format (vacation/attr->start_date vacation) time/br-day-month) | |
" → " | |
(time/format (vacation/attr->finish_date vacation) | |
time/br-day-month)]) | |
[:div | |
{:class | |
"avatar-size br-100 flex items-center justify-center b flex-none ba b--gray2 blue"} | |
(vacation/attr->amount_in_days vacation)]])))]) | |
(defn- vacation-item-spinner | |
[] | |
[:div.Vacation-listItem | |
[spinner/spinner | |
{:style {:width "50px", | |
:height "50px"}}]]) | |
(defn- vacations-list | |
[{:keys [vacations company-id]}] | |
(into [spacing/spacing | |
{:direction :vertical, | |
:size :xxl}] | |
(for [[date items] (->> vacations | |
(group-by vacation-view-key) | |
(sort-by first) | |
(reverse))] | |
^{:key date} | |
[vacation-item | |
{:company-id company-id, | |
:date date, | |
:items items}]))) | |
(defn vacations-pending-desk | |
[{:keys [company-id vacations-pending create-callback]}] | |
[table-kit/table | |
{:data vacations-pending, | |
:header [table-kit/header | |
[table-kit/cell {:width 340} "Colaborador"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Descanso"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Vender 10 dias (abono)"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Início do descanso"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Final do descanso"]], | |
:row-fn (fn [vacation] | |
(let [show-form-modal | |
(fn [] | |
(individual-modal/show-form-modal | |
{:on-delete vacation-common/handle-delete, | |
:delete-callback (fn [] | |
(vacation-common/delete-callback vacation) | |
(create-callback)), | |
:on-save vacation-common/handle-save, | |
:save-callback (fn [data] | |
(create-callback) | |
(vacation-common/save-callback | |
data | |
(vacation-common/decorate-vacations company-id))), | |
:vacation vacation, | |
:company-id company-id, | |
:profile-id (:id (vacation/->profile vacation))}))] | |
[table-kit/row | |
{:on-click show-form-modal} | |
[table-kit/cell | |
{:width 340} | |
(m-user/avatar-name-position company-id | |
(:id (vacation/->profile vacation)) | |
show-form-modal)] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(vacation/attr->amount_in_days vacation)] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(if (vacation/attr->sold_10_days vacation) | |
"Sim" | |
"Não")] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(time/format (vacation/attr->start_date vacation) time/br-date)] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(time/format (vacation/attr->finish_date vacation) time/br-date)]]))}]) | |
(defn empty-state-desktop | |
[company-id] | |
(o-empty-state/doubtful-file-card | |
[card/title {:center? true} "Ainda não sabemos o suficiente"] | |
[box/box | |
{:size :s} | |
[:p.tc | |
"Fatores como férias coletivas, períodos aquisitivos e até ausências mais longas podem influenciar no prazo e no saldo das férias de cada colaborador."] | |
[:p.tc | |
"Trate o histórico de férias da empresa para ver o relatório que vai te ajudar a evitar multas e passivos relacionados a férias"]] | |
[:div.flex.justify-center | |
(a-buttons/primary "Tratar o histórico" | |
#(path-helpers/set-token! (path-helpers/company-vacations-path | |
:importation | |
{:company-id company-id})))])) | |
(defn empty-state-mobile | |
[company-id] | |
(o-empty-state/doubtful-file | |
[card/title {:center? true} "Ainda não sabemos o suficiente"] | |
[box/box | |
{:size :s} | |
[:p.tc | |
"Fatores como férias coletivas, períodos aquisitivos e até ausências mais longas podem influenciar no prazo e no saldo das férias de cada colaborador."] | |
[:p.tc | |
"Trate o histórico de férias da empresa para ver o relatório que vai te ajudar a evitar multas e passivos relacionados a férias"]] | |
m-mobile/unavailable-warning)) | |
(defn missing-import-banner-desktop | |
[company-id to-import-number] | |
[:div | |
{:style {:box-shadow "0 1px 2px #cfcfcf", | |
:padding-left (style/sizes-string :l), | |
:padding-right (style/sizes-string :l), | |
:margin-bottom (style/sizes-string :xl)}} | |
[grid/grid | |
[grid/cell | |
{:flex 0} | |
[:div | |
{:style {:overflow "hidden", | |
:height "100px"}} | |
[:img | |
{:style {:max-width "120px"}, | |
:src (asset/image "/kitasato/static/images/empty-states/doubtful-file-alone.svg")}]]] | |
[grid/cell | |
{:flex 1} | |
[:div | |
[:p | |
[:span | |
{:style {:font-weight (str (style/font-weight :bold))}} | |
"Ainda não sabemos o suficiente sobre " | |
(if (= 1 to-import-number) | |
"1 colaborador" | |
(str to-import-number " colaboradores"))] | |
[:br] | |
[:span | |
"Trate seus históricos de férias para saber sobre o saldo e os prazos de suas próximas férias."]]]] | |
[grid/cell | |
{:flex 0, | |
:valign "center"} | |
[:div | |
{:style {:width "150px"}} | |
(a-buttons/primary "Tratar o histórico" | |
#(path-helpers/set-token! (path-helpers/company-vacations-path | |
:importation | |
{:company-id company-id})))]]]]) | |
(defn missing-import-banner-mobile | |
[to-import-number] | |
[:div | |
{:style {:box-shadow "0 1px 2px #cfcfcf", | |
:padding-left (style/sizes-string :m), | |
:padding-right (style/sizes-string :m), | |
:padding-bottom (style/sizes-string :s), | |
:margin-bottom (style/sizes-string :xl)}} | |
[:div | |
{:style {:border-bottom (str "1px solid " (style/colors :light-gray)), | |
:margin-bottom (style/sizes-string :s)}} | |
[grid/grid | |
[grid/cell | |
{:flex 1, | |
:valign :center} | |
[:div | |
[:span | |
{:style {:font-weight (str (style/font-weight :bold)), | |
:font-size (style/sizes-string :xs)}} | |
"Ainda não sabemos o suficiente sobre " | |
(if (= 1 to-import-number) | |
"1 colaborador" | |
(str to-import-number " colaboradores"))]]] | |
[grid/cell | |
{:flex 0} | |
[:div | |
{:style {:overflow "hidden", | |
:height "65px"}} | |
[:img | |
{:style {:max-width "80px"}, | |
:src (asset/image "/kitasato/static/images/empty-states/doubtful-file-alone.svg")}]]]]] | |
(a-collapse/simple | |
"Saiba mais" | |
false | |
[:div | |
[:p "Trate seus históricos de férias para saber sobre saldos e prazos das próximas férias"] | |
m-mobile/unavailable-warning])]) | |
(defn vacations-queue-desk | |
[{:keys [company-id]}] | |
(let [importation-status& (lukla/get-state [:vacation-importation :status])] | |
(fn [{:keys [vacations-queue create-callback]}] | |
(let [viewer-role (listen [:viewer/role-access])] | |
(console.log :>>>>>> viewer-role) | |
(cond | |
(:flushing? vacations-queue) [box/box | |
{:size :m, | |
:halign :center} | |
[spinner/spinner]] | |
:else | |
[:div | |
(when (not= 0 (common/attr @importation-status& :not_adjusted_profile_count)) | |
(missing-import-banner-desktop company-id | |
(common/attr @importation-status& | |
:not_adjusted_profile_count))) | |
[table-kit/table | |
{:data (:periods vacations-queue), | |
:header [table-kit/header | |
[table-kit/cell {:width 340} "Colaborador"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Saldo de Férias"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Início da Concessão"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Limite para o aviso"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
"Limite para a saída"]], | |
:row-fn | |
(fn [vacation] | |
(let [show-form-modal (fn [] | |
(individual-modal/show-form-modal | |
{:on-delete vacation-common/handle-delete, | |
:on-save vacation-common/handle-save, | |
:vacation nil, | |
:save-callback create-callback, | |
:company-id company-id, | |
:profile-id (:id (vacation/->profile vacation))}))] | |
[table-kit/row | |
{:disabled? (not (common/attr vacation :concession_started)), | |
:on-click show-form-modal} | |
[table-kit/cell | |
{:width 340} | |
(m-user/avatar-name-position company-id | |
(:id (vacation/->profile vacation)) | |
show-form-modal)] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(common/attr vacation :balance)] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(time/format (common/attr vacation :concession_start_on) time/br-date)] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(let [text (time/format (common/attr vacation :notice_limit_on) time/br-date)] | |
(if (common/attr vacation :notice_warning) | |
(typography/dangerous-text text) | |
text))] | |
[table-kit/cell | |
{:grow 1, | |
:halign :center} | |
(let [text (time/format (common/attr vacation :leave_limit_on) time/br-date)] | |
(if (common/attr vacation :leave_warning) | |
(typography/dangerous-text text) | |
text))]]))}] | |
(when (:loading? vacations-queue) | |
[box/box | |
{:size :m, | |
:halign :center} | |
[spinner/spinner]])]))))) | |
(defn vacations-queue-mobi | |
[{:keys [company-id]}] | |
(let [importation-status& (lukla/get-state [:vacation-importation :status])] | |
(fn [{:keys [vacations-queue on-create]}] | |
(if (zero? (common/attr @importation-status& :adjusted_profile_count)) | |
(empty-state-mobile company-id) | |
[:div | |
(when (not= 0 (common/attr @importation-status& :not_adjusted_profile_count)) | |
(missing-import-banner-mobile (common/attr @importation-status& | |
:not_adjusted_profile_count))) | |
(doall | |
(for [[idx period] (map-indexed vector (:periods vacations-queue)) | |
:let [handle-click #(individual-modal/show-form-modal | |
{:on-delete vacation-common/handle-delete, | |
:on-save vacation-common/handle-save, | |
:vacation nil, | |
:company-id company-id, | |
:profile-id (:id (vacation/->profile period))})]] | |
^{:key idx} | |
[box/box | |
{:size :none} | |
[card/card | |
{:on-click handle-click, | |
:disabled? (not (common/attr period :concession_started))} | |
(m-user/avatar-name-position company-id | |
(:id (vacation/->profile period)) | |
handle-click) | |
(a-layout/horizontal-divider :s) | |
[grid/grid | |
[grid/cell | |
{:size (/ 1 2)} | |
[box/box | |
{:size :none, | |
:halign :center} | |
[:div "Limite para o aviso"] | |
(let [text (time/format (common/attr period :notice_limit_on) time/br-date)] | |
(if (common/attr period :notice_warning) | |
(typography/dangerous-text text) | |
text))]] | |
[grid/cell | |
{:size (/ 1 2)} | |
[box/box | |
{:size :none, | |
:halign :center} | |
[:div "Limite para a saída"] | |
(let [text (time/format (common/attr period :leave_limit_on) time/br-date)] | |
(if (common/attr period :leave_warning) | |
(typography/dangerous-text text) | |
text))]]]] | |
(a-layout/gap :s)])) | |
(when (:loading? vacations-queue) | |
[box/box | |
{:size :m, | |
:halign :center} | |
[spinner/spinner]])])))) | |
(defn vacations-pending-mobi | |
[{:keys [vacations-pending company-id]}] | |
[table-kit/table | |
{:data vacations-pending, | |
:header [table-kit/header | |
[table-kit/cell {:grow 1} "Colaborador"] | |
[table-kit/cell | |
{:grow 1, | |
:halign :flex-end} | |
"Início"]], | |
:row-fn (fn [vacation] | |
[table-kit/row | |
{:on-click (fn [] | |
(individual-modal/show-form-modal | |
{:on-delete vacation-common/handle-delete, | |
:delete-callback (fn [] | |
(vacation-common/delete-callback vacation)), | |
:on-save vacation-common/handle-save, | |
:save-callback (fn [data] | |
(vacation-common/save-callback | |
data | |
(vacation-common/decorate-vacations | |
company-id))), | |
:vacation vacation, | |
:company-id company-id, | |
:profile-id (:id (vacation/->profile vacation))}))} | |
[table-kit/cell | |
{:grow 1} | |
(m-user/avatar-name company-id | |
(:id (vacation/->profile vacation)) | |
(str (vacation/attr->amount_in_days vacation) " dias"))] | |
[table-kit/cell | |
{:grow 1, | |
:halign :flex-end} | |
(time/format (vacation/attr->start_date vacation) time/br-date)]])}]) | |
(defn card-wrap | |
[{:keys [company-id]} _] | |
(let [open& (r/atom false)] | |
(fn [{:keys [on-create empty-view show-empty-view?]} content] | |
(if show-empty-view? | |
empty-view | |
[card/card | |
[spacing/spacing | |
{:direction :vertical, | |
:size :l} | |
[grid/grid | |
[grid/cell | |
{:flex 1, | |
:align "flex-end"} | |
[dropdown/container | |
(a-buttons/plus "Marcar férias" #(reset! open& true)) | |
[dropdown/dropdown | |
{:position :left, | |
:open? @open&, | |
:on-close #(reset! open& false)} | |
[dropdown/menu | |
[dropdown/item | |
{:data-track "add-individual-vacation", | |
:on-click (utils/maybe-handler on-create :individual)} | |
"Individual"] | |
[dropdown/item | |
{:data-track "add-collective-vacation", | |
:on-click (utils/maybe-handler on-create :collective)} | |
"Coletiva"]]]]]] | |
content]])))) | |
(defn desk | |
[{:keys [company-id on-next-page]}] | |
(let [cursor& (r/atom nil) | |
importation-status& (lukla/get-state [:vacation-importation :status])] | |
(q/select {:company-id company-id} | |
{:vacation-queue-warning [:vacation-queue-warning]} | |
#(reset! cursor& %)) | |
(scroll/bottom-wrap (utils/maybe-fn on-next-page) | |
(fn [{:keys [company-id vacations-queue default-active-tab on-change-tab], | |
:as props}] | |
[container/container | |
(a-page/title "Férias") | |
[tabs/tabs | |
{:default-active-key default-active-tab, | |
:on-change #(on-change-tab %)} | |
[tabs/item | |
{:title "Pedidos", | |
:event-key :waiting} | |
[card-wrap props [vacations-pending-desk props]]] | |
[tabs/item | |
{:title [:span | |
"Fila de Férias" | |
(when (-> @cursor& | |
:data | |
:vacation-queue-warning) | |
(a-badge/simple))], | |
:event-key :queue} | |
[card-wrap | |
(assoc props | |
:empty-view (empty-state-desktop company-id) | |
:show-empty-view? (zero? (common/attr @importation-status& :adjusted_profile_count))) | |
[vacations-queue-desk props]]] | |
[tabs/item | |
{:event-key :gannt, | |
:title "Férias marcadas"} | |
[card-wrap props [gantt props]]]]])))) | |
(defn mobile-card | |
[{:keys [loading? on-create]} content] | |
[m-mobile-frame/white-container | |
{:loading? loading?} | |
[spacing/spacing | |
{:direction :vertical, | |
:size :s} | |
[grid/grid | |
[grid/cell | |
{:flex 1, | |
:align :flex-end} | |
(a-buttons/plus-mobile (utils/maybe-handler on-create))]] | |
content]]) | |
(defn mobi | |
[{:keys [company-id on-next-page]}] | |
(let [cursor& (r/atom nil) | |
open& (r/atom false)] | |
(q/select {:company-id company-id} | |
{:vacation-queue-warning [:vacation-queue-warning]} | |
#(reset! cursor& %)) | |
(scroll/bottom-wrap on-next-page | |
(fn [{:keys [on-next-page default-active-tab on-change-tab], | |
:as props}] | |
[container/container | |
[:div.ph3.pt3 [a-page/title "Férias"]] | |
[tabs/tabs | |
{:default-active-key default-active-tab, | |
:on-change #(on-change-tab %)} | |
[tabs/item | |
{:title "Pedidos", | |
:event-key :waiting} | |
(mobile-card props [vacations-pending-mobi props])] | |
[tabs/item | |
{:title [:span | |
"Fila de Férias" | |
(when (-> @cursor& | |
:data | |
:vacation-queue-warning) | |
(a-badge/simple))], | |
:event-key :queue} | |
(mobile-card props [vacations-queue-mobi props])] | |
[tabs/item | |
{:event-key :gannt, | |
:title "Férias marcadas"} | |
(mobile-card props [vacations-list props])]]])))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment