@activecollab/components 2.0.364 → 2.0.366

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,967 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isOverdue = exports.formatDateRange = exports.dayOffset = exports.TimeCell = exports.LabelsProvider = exports.LabelCell = exports.DateCell = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _momentTimezone = _interopRequireDefault(require("moment-timezone"));
9
+ var _styledComponents = _interopRequireWildcard(require("styled-components"));
10
+ var _Button = require("../../components/Button");
11
+ var _Checkbox = require("../../components/Checkbox");
12
+ var _Chip = require("../../components/Chip");
13
+ var _DatePicker = require("../../components/DatePicker");
14
+ var _Dot = require("../../components/Dot");
15
+ var _Icons = require("../../components/Icons");
16
+ var _Input = require("../../components/Input");
17
+ var _Label = require("../../components/Label");
18
+ var _Modal = require("../../components/Modal");
19
+ var _ProgressPie = require("../../components/ProgressPie");
20
+ var _Select = require("../../components/Select");
21
+ var _SelectTrigger = require("../../components/SelectTrigger");
22
+ var _Textarea = require("../../components/Textarea");
23
+ var _Transitions = require("../../components/Transitions");
24
+ var _Typography = require("../../components/Typography");
25
+ var _utils = require("../../utils");
26
+ var _excluded = ["open", "className", "children"],
27
+ _excluded2 = ["labels"],
28
+ _excluded3 = ["value", "tooltip", "overdue"];
29
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
30
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
31
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
32
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
33
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
34
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
35
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
36
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
37
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
38
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
39
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
40
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
41
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
42
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
43
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
44
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
45
+ /**
46
+ * Interactive list-view column cells for the `Presentation/List view` story —
47
+ * the Label, Date and Time cells with their editors, mirroring
48
+ * `new-activecollab-front/src/components/ListView/columns/*`:
49
+ *
50
+ * - **Label** (`columns/Label.js` + `LabelTrigger`/`LabelItems`): chips for 1–2
51
+ * labels, dots from 3 up, `+N` past 8, and a DS `Select` picker (search,
52
+ * colored dot + label name in the label's own colour, checkbox, "+ Add new").
53
+ * - **Date** (`columns/Date.js`): a range trigger that formats like the app
54
+ * (`formatDateRange`), turns red when overdue, and opens the DS `DatePicker`
55
+ * in atomic mode so it gets the Save / ✕ / Clear footer.
56
+ * - **Time** (`columns/Time.js`): `ProgressPie` + `tracked/estimated`, coloured
57
+ * by how much of the estimate is used, opening the "Add Time Record" dialog.
58
+ *
59
+ * Everything is local state — there is no store, so edits live as long as the
60
+ * story is mounted.
61
+ */
62
+
63
+ var SANS = '-apple-system, BlinkMacSystemFont, "Inter", "Roboto", "Helvetica Neue", Arial, sans-serif';
64
+
65
+ /**
66
+ * CSS-only tooltip, mirroring the app's `.c-cooltip.c-cooltip--top` (see
67
+ * `styles/c_cooltip.less`). The list renders hundreds of these, and the DS
68
+ * `Tooltip` mounts a Portal + Popper per instance — far too heavy per cell — so
69
+ * the cells use `data-tooltip` exactly like the real list view does.
70
+ */
71
+ var CooltipStyle = (0, _styledComponents.css)(["&[data-tooltip],[data-tooltip]{position:relative;}&[data-tooltip]::after,[data-tooltip]::after{pointer-events:none;content:attr(data-tooltip);position:absolute;bottom:calc(100% + 0.5rem);left:50%;transform:scale(0.85) translateX(-50%);transform-origin:0;opacity:0;max-width:12.5rem;padding:0.25rem 0.625rem;border-radius:0.5rem;background-color:rgba(0,0,0,0.9);color:#fff;font-family:", ";font-size:0.75rem;font-weight:500;line-height:1.3;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}@media (hover:hover){&[data-tooltip]:not(:focus):hover::after,[data-tooltip]:not(:focus):hover::after{transition:opacity 0.15s ease,transform 0.15s ease;transition-delay:0.6s;transform:scale(1) translateX(-50%);opacity:1;}}"], SANS);
72
+
73
+ /* ================================================================== */
74
+ /* Shared trigger button (mirrors ListView/ListButton.js) */
75
+ /* ================================================================== */
76
+
77
+ /**
78
+ * `Menu` clones its `target` and injects `open`, so — like the app's
79
+ * `ListButton` — the trigger has to swallow that prop and turn it into the DS
80
+ * `active` state plus an `.open` class the row CSS uses to keep the trigger
81
+ * visible while its menu is open.
82
+ */
83
+ var ListButtonBase = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
84
+ var open = _ref.open,
85
+ className = _ref.className,
86
+ children = _ref.children,
87
+ rest = _objectWithoutProperties(_ref, _excluded);
88
+ return /*#__PURE__*/_react.default.createElement(_Button.Button, _extends({}, rest, {
89
+ ref: ref,
90
+ type: "button",
91
+ variant: "text gray",
92
+ active: open,
93
+ className: "list-button".concat(className ? " ".concat(className) : "").concat(open ? " open" : "")
94
+ }), children);
95
+ });
96
+ ListButtonBase.displayName = "ListButtonBase";
97
+
98
+ /*
99
+ * The DS Button treats a single element child as "icon only" — inline-flex,
100
+ * centered, a fixed 32px wide and `overflow: hidden`, which squashes a date or
101
+ * a chip. `&&` doubles the specificity so these rules win over that block; the
102
+ * button then hugs its content and the column's `justify-content: flex-end`
103
+ * parks it against the right edge.
104
+ */
105
+ var StyledListButton = (0, _styledComponents.default)(ListButtonBase).withConfig({
106
+ displayName: "columns__StyledListButton",
107
+ componentId: "sc-9f4385-0"
108
+ })(["&&{display:inline-flex;align-items:center;justify-content:flex-end;width:auto;min-width:0;max-width:100%;padding:4px 8px;overflow:visible;text-align:right;}", ""], CooltipStyle);
109
+
110
+ /* ================================================================== */
111
+ /* Labels */
112
+ /* ================================================================== */
113
+
114
+ /* The project's label catalogue. Names are uppercase, like in the app. */
115
+ var INITIAL_LABELS = [{
116
+ id: "in-progress",
117
+ name: "IN PROGRESS",
118
+ color: "#CDE8F5",
119
+ textColor: "#3D7F9E"
120
+ }, {
121
+ id: "needs-review",
122
+ name: "NEEDS REVIEW",
123
+ color: "#F9E79F",
124
+ textColor: "#A98A17"
125
+ }, {
126
+ id: "approved",
127
+ name: "APPROVED",
128
+ color: "#A9DFBF",
129
+ textColor: "#3D9A6A"
130
+ }, {
131
+ id: "blocked",
132
+ name: "BLOCKED",
133
+ color: "#F1948A",
134
+ textColor: "#B5544C"
135
+ }, {
136
+ id: "on-hold",
137
+ name: "ON HOLD",
138
+ color: "#F5CBA7",
139
+ textColor: "#B4713A"
140
+ }, {
141
+ id: "idea",
142
+ name: "IDEA",
143
+ color: "#FAD7A0",
144
+ textColor: "#B98A2B"
145
+ }, {
146
+ id: "todo",
147
+ name: "TODO",
148
+ color: "#D6EAF8",
149
+ textColor: "#4A87B5"
150
+ }, {
151
+ id: "research",
152
+ name: "RESEARCH",
153
+ color: "#D7BDE2",
154
+ textColor: "#8155A0"
155
+ }, {
156
+ id: "accessibility",
157
+ name: "ACCESSIBILITY",
158
+ color: "#AED6F1",
159
+ textColor: "#3E7CA6"
160
+ }, {
161
+ id: "copy",
162
+ name: "COPY",
163
+ color: "#F5B7B1",
164
+ textColor: "#B5544C"
165
+ }, {
166
+ id: "design-debt",
167
+ name: "DESIGN DEBT",
168
+ color: "#E8DAEF",
169
+ textColor: "#7D5A99"
170
+ }, {
171
+ id: "qa",
172
+ name: "QA",
173
+ color: "#A3E4D7",
174
+ textColor: "#34907C"
175
+ }, {
176
+ id: "client-input",
177
+ name: "CLIENT INPUT",
178
+ color: "#FDEBD0",
179
+ textColor: "#B08640"
180
+ }, {
181
+ id: "mobile",
182
+ name: "MOBILE",
183
+ color: "#D1F2EB",
184
+ textColor: "#2E8B7A"
185
+ }, {
186
+ id: "performance",
187
+ name: "PERFORMANCE",
188
+ color: "#FCF3CF",
189
+ textColor: "#A38B1E"
190
+ }, {
191
+ id: "asset",
192
+ name: "ASSET",
193
+ color: "#D5D8DC",
194
+ textColor: "#6B7378"
195
+ }];
196
+
197
+ /* Colours handed out to labels created from the picker's "+ Add new" row. */
198
+ var NEW_LABEL_COLORS = [{
199
+ color: "#F9E0F2",
200
+ textColor: "#A4569B"
201
+ }, {
202
+ color: "#DDEBFB",
203
+ textColor: "#4E7BA8"
204
+ }, {
205
+ color: "#E4F6D8",
206
+ textColor: "#5F9440"
207
+ }, {
208
+ color: "#FDE2D5",
209
+ textColor: "#B36A45"
210
+ }];
211
+ var LabelsContext = /*#__PURE__*/(0, _react.createContext)({
212
+ labels: INITIAL_LABELS,
213
+ labelsById: {},
214
+ addLabel: function addLabel() {
215
+ return "";
216
+ }
217
+ });
218
+
219
+ /**
220
+ * Holds the label catalogue for the whole list, so a label created in one
221
+ * task's picker shows up in every other picker too.
222
+ */
223
+ var LabelsProvider = exports.LabelsProvider = function LabelsProvider(_ref2) {
224
+ var children = _ref2.children;
225
+ var _useState = (0, _react.useState)(INITIAL_LABELS),
226
+ _useState2 = _slicedToArray(_useState, 2),
227
+ labels = _useState2[0],
228
+ setLabels = _useState2[1];
229
+ var addLabel = (0, _react.useCallback)(function (name) {
230
+ var trimmed = name.trim().toUpperCase();
231
+ var id = "label-".concat(trimmed.toLowerCase().replace(/[^a-z0-9]+/g, "-"));
232
+ setLabels(function (prev) {
233
+ if (prev.some(function (label) {
234
+ return label.id === id;
235
+ })) {
236
+ return prev;
237
+ }
238
+ var palette = NEW_LABEL_COLORS[prev.length % NEW_LABEL_COLORS.length];
239
+ return [...prev, _objectSpread({
240
+ id,
241
+ name: trimmed
242
+ }, palette)];
243
+ });
244
+ return id;
245
+ }, []);
246
+ var value = (0, _react.useMemo)(function () {
247
+ return {
248
+ labels,
249
+ labelsById: labels.reduce(function (acc, label) {
250
+ return _objectSpread(_objectSpread({}, acc), {}, {
251
+ [label.id]: label
252
+ });
253
+ }, {}),
254
+ addLabel
255
+ };
256
+ }, [addLabel, labels]);
257
+ return /*#__PURE__*/_react.default.createElement(LabelsContext.Provider, {
258
+ value: value
259
+ }, children);
260
+ };
261
+ var useTaskLabels = function useTaskLabels() {
262
+ return (0, _react.useContext)(LabelsContext);
263
+ };
264
+
265
+ /* Empty state pill (mirrors EntityLabel + .entity-label in list-view.less) */
266
+ var StyledLabelPlaceholder = _styledComponents.default.span.withConfig({
267
+ displayName: "columns__StyledLabelPlaceholder",
268
+ componentId: "sc-9f4385-1"
269
+ })(["display:inline-flex;align-items:center;padding:1px 6px;border:1px solid var(--color-theme-700);border-radius:4px;.list-button.open &,.list-button:hover &{border-color:var(--color-primary-700,var(--color-primary));}"]);
270
+ var StyledLabelItems = _styledComponents.default.span.withConfig({
271
+ displayName: "columns__StyledLabelItems",
272
+ componentId: "sc-9f4385-2"
273
+ })(["display:inline-flex;align-items:center;min-width:0;> *:not(:last-child){margin-right:2px;}.rest-count{margin-left:2px;}", ""], CooltipStyle);
274
+ var MAX_SHOWN_LABELS = 8;
275
+ var LabelItems = function LabelItems(_ref3) {
276
+ var labels = _ref3.labels;
277
+ var showAsDot = labels.length > 2;
278
+ var shown = labels;
279
+ var restCount = 0;
280
+ if (labels.length > MAX_SHOWN_LABELS) {
281
+ restCount = Math.min(labels.length - MAX_SHOWN_LABELS, 99);
282
+ shown = labels.slice(0, MAX_SHOWN_LABELS - 1);
283
+ }
284
+ return /*#__PURE__*/_react.default.createElement(StyledLabelItems, null, shown.map(function (label) {
285
+ return showAsDot ? /*#__PURE__*/_react.default.createElement(_Dot.Dot, {
286
+ key: label.id,
287
+ color: label.color,
288
+ size: 20,
289
+ "data-tooltip": label.name
290
+ }) : /*#__PURE__*/_react.default.createElement(_Chip.Chip, {
291
+ key: label.id,
292
+ label: label.name,
293
+ backgroundColor: label.color,
294
+ color: "#303037",
295
+ style: {
296
+ maxWidth: "90px"
297
+ },
298
+ typographyProps: {
299
+ variant: "Caption 2",
300
+ weight: "bold"
301
+ },
302
+ "data-tooltip": label.name
303
+ });
304
+ }), restCount > 0 ? /*#__PURE__*/_react.default.createElement(_Typography.Body2, {
305
+ weight: "bold",
306
+ className: "rest-count"
307
+ }, "+", restCount) : null);
308
+ };
309
+ var LabelTrigger = /*#__PURE__*/(0, _react.forwardRef)(function (_ref4, ref) {
310
+ var labels = _ref4.labels,
311
+ rest = _objectWithoutProperties(_ref4, _excluded2);
312
+ if (labels.length === 0) {
313
+ return /*#__PURE__*/_react.default.createElement(StyledListButton, _extends({}, rest, {
314
+ ref: ref,
315
+ className: "show-on-hover",
316
+ "aria-label": "Add labels",
317
+ "data-tooltip": "Add Labels"
318
+ }), /*#__PURE__*/_react.default.createElement(StyledLabelPlaceholder, null, /*#__PURE__*/_react.default.createElement(_Typography.Caption2, {
319
+ weight: "bold",
320
+ color: "tertiary"
321
+ }, "LABEL")));
322
+ }
323
+ return /*#__PURE__*/_react.default.createElement(StyledListButton, _extends({}, rest, {
324
+ ref: ref,
325
+ "aria-label": "Change labels"
326
+ }), /*#__PURE__*/_react.default.createElement(LabelItems, {
327
+ labels: labels
328
+ }));
329
+ });
330
+ LabelTrigger.displayName = "LabelTrigger";
331
+ var LabelCell = exports.LabelCell = function LabelCell(_ref5) {
332
+ var labelIds = _ref5.labelIds,
333
+ _ref5$completed = _ref5.completed,
334
+ completed = _ref5$completed === void 0 ? false : _ref5$completed;
335
+ var _useTaskLabels = useTaskLabels(),
336
+ catalog = _useTaskLabels.labels,
337
+ labelsById = _useTaskLabels.labelsById,
338
+ addLabel = _useTaskLabels.addLabel;
339
+ var _useState3 = (0, _react.useState)(labelIds !== null && labelIds !== void 0 ? labelIds : []),
340
+ _useState4 = _slicedToArray(_useState3, 2),
341
+ selected = _useState4[0],
342
+ setSelected = _useState4[1];
343
+
344
+ /* alphabetical, like LabelTrigger sorts before rendering */
345
+ var selectedLabels = (0, _react.useMemo)(function () {
346
+ return selected.map(function (id) {
347
+ return labelsById[id];
348
+ }).filter(function (label) {
349
+ return Boolean(label);
350
+ }).sort(function (a, b) {
351
+ return a.name.localeCompare(b.name);
352
+ });
353
+ }, [labelsById, selected]);
354
+ var options = (0, _react.useMemo)(function () {
355
+ return catalog.map(function (label) {
356
+ return {
357
+ id: label.id,
358
+ name: label.name,
359
+ color: label.color,
360
+ textColor: label.textColor
361
+ };
362
+ });
363
+ }, [catalog]);
364
+ var handleChange = (0, _react.useCallback)(function (value) {
365
+ setSelected(Array.isArray(value) ? value.map(String) : [String(value)].filter(Boolean));
366
+ }, []);
367
+ var handleAddNew = (0, _react.useCallback)(function (name) {
368
+ if (!name || !name.trim()) {
369
+ return;
370
+ }
371
+ var id = addLabel(name);
372
+ setSelected(function (prev) {
373
+ return prev.includes(id) ? prev : [...prev, id];
374
+ });
375
+ }, [addLabel]);
376
+
377
+ /* Completed tasks show their labels read-only (mirrors Label.js) */
378
+ if (completed) {
379
+ return /*#__PURE__*/_react.default.createElement(StyledReadOnlyCell, {
380
+ className: "col col-label"
381
+ }, selectedLabels.length > 0 ? /*#__PURE__*/_react.default.createElement(LabelItems, {
382
+ labels: selectedLabels
383
+ }) : null);
384
+ }
385
+ return /*#__PURE__*/_react.default.createElement("div", {
386
+ className: "col col-label"
387
+ }, /*#__PURE__*/_react.default.createElement(_Select.Select, {
388
+ type: "multiple",
389
+ options: options,
390
+ selected: selected,
391
+ onChange: handleChange,
392
+ emptyValue: "Add new",
393
+ emptyAction: handleAddNew,
394
+ autoHeightMax: 278,
395
+ position: "bottom-end",
396
+ target: /*#__PURE__*/_react.default.createElement(LabelTrigger, {
397
+ labels: selectedLabels
398
+ })
399
+ }));
400
+ };
401
+
402
+ /* ================================================================== */
403
+ /* Date */
404
+ /* ================================================================== */
405
+
406
+ /** The personalized date format the app defaults to (`MMM D. YYYY`). */
407
+ var DATE_FORMAT = "MMM D. YYYY";
408
+
409
+ /** Midnight UTC today — the reference point for the mock data and overdue. */
410
+ var todayUnix = function todayUnix() {
411
+ return _momentTimezone.default.utc().startOf("day").unix();
412
+ };
413
+
414
+ /** Build a mock timestamp N days from today (negative = in the past). */
415
+ var dayOffset = exports.dayOffset = function dayOffset(offset) {
416
+ return _momentTimezone.default.utc().startOf("day").add(offset, "days").unix();
417
+ };
418
+
419
+ /** mirrors utils/date.js → formatDateRange (month-first format) */
420
+ var formatDateRange = exports.formatDateRange = function formatDateRange(from, to) {
421
+ if (from === undefined || from === null) {
422
+ return undefined;
423
+ }
424
+ var start = _momentTimezone.default.unix(from).utc();
425
+ var due = _momentTimezone.default.unix(to !== null && to !== void 0 ? to : from).utc();
426
+ var withoutYear = DATE_FORMAT.replace(/YYYY|,$/gi, "").trim();
427
+ var withoutYearAndMonth = withoutYear.replace(/MMM|,$/gi, "").trim();
428
+ if (from === to || to === undefined) {
429
+ return start.format(withoutYear);
430
+ }
431
+ if (start.year() === due.year() && start.month() === due.month()) {
432
+ return "".concat(start.format(withoutYear), " - ").concat(due.format(withoutYearAndMonth));
433
+ }
434
+ return "".concat(start.format(withoutYear), " - ").concat(due.format(withoutYear));
435
+ };
436
+
437
+ /** mirrors utils/date.js → formatDateSmart(…, long) */
438
+ var formatDateLong = function formatDateLong(value) {
439
+ return value ? _momentTimezone.default.unix(value).utc().format(DATE_FORMAT) : "";
440
+ };
441
+ var isOverdue = exports.isOverdue = function isOverdue(dueOn, completed) {
442
+ return Boolean(dueOn && !completed && dueOn < todayUnix());
443
+ };
444
+ var StyledDateValue = _styledComponents.default.span.withConfig({
445
+ displayName: "columns__StyledDateValue",
446
+ componentId: "sc-9f4385-3"
447
+ })(["font-family:", ";white-space:nowrap;"], SANS);
448
+
449
+ /* completed rows render values without a trigger, so the cell itself hosts the
450
+ CSS tooltip */
451
+ var StyledReadOnlyCell = _styledComponents.default.div.withConfig({
452
+ displayName: "columns__StyledReadOnlyCell",
453
+ componentId: "sc-9f4385-4"
454
+ })(["padding-right:8px;", ""], CooltipStyle);
455
+
456
+ /**
457
+ * `DatePicker` wraps itself in a `width: 100%` inline-block, which would stretch
458
+ * across the column and left-align the trigger the moment the picker mounts —
459
+ * the value would visibly jump and the popper would anchor to the wrong spot.
460
+ * Keeping that wrapper right-aligned makes the open state geometrically
461
+ * identical to the closed one.
462
+ */
463
+ var StyledPickerCell = _styledComponents.default.div.withConfig({
464
+ displayName: "columns__StyledPickerCell",
465
+ componentId: "sc-9f4385-5"
466
+ })(["> div{text-align:right;}"]);
467
+ var DateTrigger = /*#__PURE__*/(0, _react.forwardRef)(function (_ref6, ref) {
468
+ var value = _ref6.value,
469
+ tooltip = _ref6.tooltip,
470
+ overdue = _ref6.overdue,
471
+ rest = _objectWithoutProperties(_ref6, _excluded3);
472
+ return /*#__PURE__*/_react.default.createElement(StyledListButton, _extends({}, rest, {
473
+ ref: ref,
474
+ className: value ? "show-on-hover has-value" : "show-on-hover",
475
+ "aria-label": value ? "Change dates" : "Add date",
476
+ "data-tooltip": tooltip
477
+ }), value ? /*#__PURE__*/_react.default.createElement(StyledDateValue, null, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
478
+ weight: "bold",
479
+ color: overdue ? "alert" : "secondary"
480
+ }, value)) : /*#__PURE__*/_react.default.createElement(_Icons.CalendarIcon, null));
481
+ });
482
+ DateTrigger.displayName = "DateTrigger";
483
+ var DateCell = exports.DateCell = function DateCell(_ref7) {
484
+ var _dates$from, _dates$to2;
485
+ var startOn = _ref7.startOn,
486
+ dueOn = _ref7.dueOn,
487
+ _ref7$completed = _ref7.completed,
488
+ completed = _ref7$completed === void 0 ? false : _ref7$completed;
489
+ var _useState5 = (0, _react.useState)({
490
+ from: startOn,
491
+ to: dueOn
492
+ }),
493
+ _useState6 = _slicedToArray(_useState5, 2),
494
+ dates = _useState6[0],
495
+ setDates = _useState6[1];
496
+ /**
497
+ * The DS `DatePicker` does real work on mount (timezone guess, month grids,
498
+ * key handlers) — with one per row that is the single most expensive thing on
499
+ * this page. So the closed state is just the trigger; the picker is mounted
500
+ * on first click, already open, and unmounted again when it closes.
501
+ */
502
+ var _useState7 = (0, _react.useState)(false),
503
+ _useState8 = _slicedToArray(_useState7, 2),
504
+ pickerMounted = _useState8[0],
505
+ setPickerMounted = _useState8[1];
506
+
507
+ /* moment isn't cheap either; only reformat when the dates actually change */
508
+ var _useMemo = (0, _react.useMemo)(function () {
509
+ var _dates$to;
510
+ var formatted = formatDateRange(dates.from, dates.to);
511
+ var hint = "Add Date";
512
+ if (dates.from) {
513
+ hint = !dates.to || dates.to === dates.from ? formatDateLong(dates.from) : "".concat(formatDateLong(dates.from), " - ").concat(formatDateLong(dates.to));
514
+ }
515
+ return {
516
+ value: formatted,
517
+ overdue: isOverdue((_dates$to = dates.to) !== null && _dates$to !== void 0 ? _dates$to : dates.from, completed),
518
+ tooltip: hint
519
+ };
520
+ }, [completed, dates.from, dates.to]),
521
+ value = _useMemo.value,
522
+ overdue = _useMemo.overdue,
523
+ tooltip = _useMemo.tooltip;
524
+ var handleSave = (0, _react.useCallback)(function (range) {
525
+ if (!range || range.from === null || range.from === undefined) {
526
+ setDates({});
527
+ return;
528
+ }
529
+ setDates({
530
+ from: Number(range.from),
531
+ to: range.to ? Number(range.to) : Number(range.from)
532
+ });
533
+ }, []);
534
+ var handleClear = (0, _react.useCallback)(function () {
535
+ return setDates({});
536
+ }, []);
537
+ var handleCalendarToggle = (0, _react.useCallback)(function (next) {
538
+ if (!next) {
539
+ setPickerMounted(false);
540
+ }
541
+ }, []);
542
+
543
+ /* Completed tasks show the date read-only (mirrors Date.js) */
544
+ if (completed) {
545
+ return /*#__PURE__*/_react.default.createElement(StyledReadOnlyCell, {
546
+ className: "col col-date"
547
+ }, value ? /*#__PURE__*/_react.default.createElement(StyledDateValue, {
548
+ "data-tooltip": tooltip
549
+ }, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
550
+ weight: "bold",
551
+ color: overdue ? "alert" : "secondary"
552
+ }, value)) : null);
553
+ }
554
+ if (!pickerMounted) {
555
+ return /*#__PURE__*/_react.default.createElement("div", {
556
+ className: "col col-date"
557
+ }, /*#__PURE__*/_react.default.createElement(DateTrigger, {
558
+ value: value,
559
+ tooltip: tooltip,
560
+ overdue: overdue,
561
+ onClick: function onClick() {
562
+ return setPickerMounted(true);
563
+ }
564
+ }));
565
+ }
566
+ return /*#__PURE__*/_react.default.createElement(StyledPickerCell, {
567
+ className: "col col-date"
568
+ }, /*#__PURE__*/_react.default.createElement(_DatePicker.DatePicker, {
569
+ open: true,
570
+ mode: "custom",
571
+ instant: false,
572
+ maxRange: 366,
573
+ firstDayOfWeek: 1,
574
+ position: "bottom-end",
575
+ selected: {
576
+ from: (_dates$from = dates.from) !== null && _dates$from !== void 0 ? _dates$from : null,
577
+ to: (_dates$to2 = dates.to) !== null && _dates$to2 !== void 0 ? _dates$to2 : null
578
+ },
579
+ onSave: handleSave,
580
+ onClear: handleClear,
581
+ onCalendarToggle: handleCalendarToggle,
582
+ target: /*#__PURE__*/_react.default.createElement(DateTrigger, {
583
+ value: value,
584
+ tooltip: tooltip,
585
+ overdue: overdue
586
+ })
587
+ }));
588
+ };
589
+
590
+ /* ================================================================== */
591
+ /* Time */
592
+ /* ================================================================== */
593
+
594
+ /** mirrors utils/utils.jsx → calculateTimeToEstimatePercentage */
595
+ var timeToEstimatePercentage = function timeToEstimatePercentage(tracked, estimated) {
596
+ if (estimated > 0) {
597
+ return tracked > 0 ? Math.round(tracked / estimated * 100) : 0;
598
+ }
599
+ return null;
600
+ };
601
+
602
+ /** mirrors utils/utils.jsx → formatTrackedAndEstimatedTime */
603
+ var formatTrackedAndEstimated = function formatTrackedAndEstimated(tracked, estimated) {
604
+ return estimated > 0 ? "".concat((0, _utils.formatHours)(tracked, false, false, "short"), "/").concat((0, _utils.formatHours)(estimated, false, false, "short")) : (0, _utils.formatHours)(tracked, false, false, "short");
605
+ };
606
+
607
+ /* mirrors Time.js → progressColor() */
608
+ var progressColor = function progressColor(percent) {
609
+ if (percent >= 100) {
610
+ return "var(--red-alert)";
611
+ }
612
+ if (percent >= 75) {
613
+ return "var(--warning)";
614
+ }
615
+ return "var(--color-sucess-green)";
616
+ };
617
+ var StyledTimeValue = _styledComponents.default.span.withConfig({
618
+ displayName: "columns__StyledTimeValue",
619
+ componentId: "sc-9f4385-6"
620
+ })(["display:inline-flex;align-items:center;font-family:", ";white-space:nowrap;.c-progress-pie,svg{flex-shrink:0;}.time-pie{margin-right:8px;}"], SANS);
621
+ var TimeValue = function TimeValue(_ref8) {
622
+ var tracked = _ref8.tracked,
623
+ estimated = _ref8.estimated;
624
+ var percent = timeToEstimatePercentage(tracked, estimated);
625
+ return /*#__PURE__*/_react.default.createElement(StyledTimeValue, null, estimated > 0 ? /*#__PURE__*/_react.default.createElement(_ProgressPie.ProgressPie, {
626
+ className: "time-pie",
627
+ radius: 10,
628
+ progress: percent !== null && percent !== void 0 ? percent : 0,
629
+ progressColor: progressColor(percent !== null && percent !== void 0 ? percent : 0),
630
+ backgroundColor: "var(--color-theme-300)"
631
+ }) : null, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
632
+ weight: "bold"
633
+ }, formatTrackedAndEstimated(tracked, estimated)));
634
+ };
635
+ var TimeTrigger = function TimeTrigger(_ref9) {
636
+ var tracked = _ref9.tracked,
637
+ estimated = _ref9.estimated,
638
+ onClick = _ref9.onClick;
639
+ var hasTime = tracked > 0 || estimated > 0;
640
+ return /*#__PURE__*/_react.default.createElement(StyledListButton, {
641
+ onClick: onClick,
642
+ className: hasTime ? "show-on-hover open" : "show-on-hover",
643
+ "aria-label": hasTime ? "Edit time" : "Add time",
644
+ "data-tooltip": hasTime ? "Edit Time" : "Add Time"
645
+ }, hasTime ? /*#__PURE__*/_react.default.createElement(TimeValue, {
646
+ tracked: tracked,
647
+ estimated: estimated
648
+ }) : /*#__PURE__*/_react.default.createElement(_Icons.ClockAddIcon, null));
649
+ };
650
+ var TimeCell = exports.TimeCell = function TimeCell(_ref0) {
651
+ var taskName = _ref0.taskName,
652
+ _ref0$tracked = _ref0.tracked,
653
+ tracked = _ref0$tracked === void 0 ? 0 : _ref0$tracked,
654
+ _ref0$estimated = _ref0.estimated,
655
+ estimated = _ref0$estimated === void 0 ? 0 : _ref0$estimated,
656
+ users = _ref0.users,
657
+ currentUserId = _ref0.currentUserId,
658
+ _ref0$completed = _ref0.completed,
659
+ completed = _ref0$completed === void 0 ? false : _ref0$completed;
660
+ var _useState9 = (0, _react.useState)(false),
661
+ _useState0 = _slicedToArray(_useState9, 2),
662
+ open = _useState0[0],
663
+ setOpen = _useState0[1];
664
+ var _useState1 = (0, _react.useState)(function () {
665
+ var _users$find$name, _users$find;
666
+ return tracked > 0 ? [{
667
+ id: 1,
668
+ date: dayOffset(-3),
669
+ userId: currentUserId,
670
+ userName: (_users$find$name = (_users$find = users.find(function (user) {
671
+ return user.id === currentUserId;
672
+ })) === null || _users$find === void 0 ? void 0 : _users$find.name) !== null && _users$find$name !== void 0 ? _users$find$name : "You",
673
+ jobType: "Design",
674
+ hours: tracked,
675
+ billable: true
676
+ }] : [];
677
+ }),
678
+ _useState10 = _slicedToArray(_useState1, 2),
679
+ records = _useState10[0],
680
+ setRecords = _useState10[1];
681
+ var total = (0, _react.useMemo)(function () {
682
+ return records.reduce(function (sum, record) {
683
+ return sum + record.hours;
684
+ }, 0);
685
+ }, [records]);
686
+ var handleAdd = (0, _react.useCallback)(function (record) {
687
+ setRecords(function (prev) {
688
+ return [_objectSpread(_objectSpread({}, record), {}, {
689
+ id: prev.length + 1
690
+ }), ...prev];
691
+ });
692
+ setOpen(false);
693
+ }, []);
694
+
695
+ /* Completed tasks show the value without the "add" affordance (mirrors
696
+ Time.js passing hideIcon for completed tasks) */
697
+ if (completed) {
698
+ return /*#__PURE__*/_react.default.createElement(StyledReadOnlyCell, {
699
+ className: "col col-time"
700
+ }, total > 0 || estimated > 0 ? /*#__PURE__*/_react.default.createElement(TimeValue, {
701
+ tracked: total,
702
+ estimated: estimated
703
+ }) : null);
704
+ }
705
+ return /*#__PURE__*/_react.default.createElement("div", {
706
+ className: "col col-time"
707
+ }, /*#__PURE__*/_react.default.createElement(TimeTrigger, {
708
+ tracked: total,
709
+ estimated: estimated,
710
+ onClick: function onClick() {
711
+ return setOpen(true);
712
+ }
713
+ }), open ? /*#__PURE__*/_react.default.createElement(TimeRecordDialog, {
714
+ open: open,
715
+ taskName: taskName,
716
+ users: users,
717
+ currentUserId: currentUserId,
718
+ records: records,
719
+ total: total,
720
+ onSubmit: handleAdd,
721
+ onClose: function onClose() {
722
+ return setOpen(false);
723
+ }
724
+ }) : null);
725
+ };
726
+
727
+ /* ------------------------------------------------------------------ */
728
+ /* Add Time Record dialog (mirrors TimeRecordForm/*) */
729
+ /* ------------------------------------------------------------------ */
730
+
731
+ var JOB_TYPES = [{
732
+ id: "design",
733
+ name: "Design"
734
+ }, {
735
+ id: "development",
736
+ name: "Development"
737
+ }, {
738
+ id: "devops",
739
+ name: "Devops"
740
+ }, {
741
+ id: "consulting",
742
+ name: "Consulting"
743
+ }, {
744
+ id: "qa",
745
+ name: "QA"
746
+ }];
747
+
748
+ /* The dialog paper — the app builds this one by hand rather than with DS
749
+ `Dialog` because it is 770px wide (`.time_record_form_modal_wrapper`). */
750
+ var StyledTimeRecordPaper = _styledComponents.default.div.withConfig({
751
+ displayName: "columns__StyledTimeRecordPaper",
752
+ componentId: "sc-9f4385-7"
753
+ })(["position:relative;width:770px;max-width:95vw;max-height:calc(100vh - 156px);margin:126px auto 30px auto;padding:20px 30px;overflow:auto;border-radius:8px;background-color:var(--page-paper-main);color:var(--color-theme-900);box-shadow:var(--shadow-primary);box-sizing:border-box;font-family:", ";*{box-sizing:border-box;}@media (max-width:830px){width:calc(100vw - 60px);}.trd-header{display:flex;align-items:center;justify-content:space-between;}.trd-title{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;margin-right:16px;font-size:1rem;font-weight:700;}.trd-date button{width:auto;}.trd-date > div{text-align:right;}.trd-divider{margin:20px 0 32px 0;border-bottom:1px solid var(--border-primary);height:1px;}.trd-body{display:flex;justify-content:space-between;position:relative;}.trd-form{width:100%;}.trd-fields{display:flex;align-items:flex-end;}.trd-hours{width:144px;margin-right:16px;flex-shrink:0;}.trd-hours .c-input-wrapper,.trd-hours input{width:100%;}.trd-field{margin-right:16px;}.trd-field:last-of-type{margin-right:20px;}.trd-field .c-label{display:block;margin-bottom:2px;}.trd-field button{width:144px;}.trd-billable{display:flex;align-items:center;margin-top:24px;}.trd-billable .c-label{margin-left:8px;cursor:pointer;}.trd-description-trigger{display:inline-flex;align-items:center;margin-top:16px;color:var(--color-secondary);font-size:14px;font-weight:500;background:none;border:none;padding:0;cursor:pointer;font-family:", ";}.trd-description-trigger svg{margin-right:4px;fill:var(--color-primary);transition:transform 200ms ease;}.trd-description-trigger.collapsed svg{transform:rotate(180deg);}.trd-textarea{width:360px;max-width:100%;margin-top:8px;font-size:12px;resize:none;}.trd-actions{display:flex;margin-top:24px;}.trd-actions .c-button:first-child{margin-right:12px;}.trd-total{position:absolute;right:0;bottom:0;display:inline-flex;align-items:center;align-self:flex-end;background:none;border:none;padding:0;cursor:pointer;}.trd-total svg{margin-right:4px;fill:var(--color-primary);transition:transform 200ms ease;}.trd-total.collapsed svg{transform:rotate(180deg);}.trd-records{margin-top:32px;border-top:1px solid var(--border-primary);}.trd-record{display:flex;align-items:center;justify-content:space-between;height:36px;border-bottom:1px solid var(--color-theme-300);}.trd-record-left{display:flex;align-items:center;gap:12px;min-width:0;}"], SANS, SANS);
754
+ var TimeRecordDialog = function TimeRecordDialog(_ref1) {
755
+ var open = _ref1.open,
756
+ taskName = _ref1.taskName,
757
+ users = _ref1.users,
758
+ currentUserId = _ref1.currentUserId,
759
+ records = _ref1.records,
760
+ total = _ref1.total,
761
+ onSubmit = _ref1.onSubmit,
762
+ onClose = _ref1.onClose;
763
+ var _useState11 = (0, _react.useState)(""),
764
+ _useState12 = _slicedToArray(_useState11, 2),
765
+ value = _useState12[0],
766
+ setValue = _useState12[1];
767
+ var _useState13 = (0, _react.useState)(todayUnix()),
768
+ _useState14 = _slicedToArray(_useState13, 2),
769
+ date = _useState14[0],
770
+ setDate = _useState14[1];
771
+ var _useState15 = (0, _react.useState)(currentUserId),
772
+ _useState16 = _slicedToArray(_useState15, 2),
773
+ userId = _useState16[0],
774
+ setUserId = _useState16[1];
775
+ var _useState17 = (0, _react.useState)("devops"),
776
+ _useState18 = _slicedToArray(_useState17, 2),
777
+ jobTypeId = _useState18[0],
778
+ setJobTypeId = _useState18[1];
779
+ var _useState19 = (0, _react.useState)(false),
780
+ _useState20 = _slicedToArray(_useState19, 2),
781
+ billable = _useState20[0],
782
+ setBillable = _useState20[1];
783
+ var _useState21 = (0, _react.useState)(true),
784
+ _useState22 = _slicedToArray(_useState21, 2),
785
+ showDescription = _useState22[0],
786
+ setShowDescription = _useState22[1];
787
+ var _useState23 = (0, _react.useState)(""),
788
+ _useState24 = _slicedToArray(_useState23, 2),
789
+ description = _useState24[0],
790
+ setDescription = _useState24[1];
791
+ var _useState25 = (0, _react.useState)(false),
792
+ _useState26 = _slicedToArray(_useState25, 2),
793
+ showRecords = _useState26[0],
794
+ setShowRecords = _useState26[1];
795
+ var user = users.find(function (item) {
796
+ return item.id === userId;
797
+ });
798
+ var jobType = JOB_TYPES.find(function (item) {
799
+ return item.id === jobTypeId;
800
+ });
801
+
802
+ /** "1:30" / "1.5" → decimal hours */
803
+ var hours = (0, _react.useMemo)(function () {
804
+ var trimmed = value.trim();
805
+ if (!trimmed) {
806
+ return 0;
807
+ }
808
+ if (trimmed.includes(":")) {
809
+ var _trimmed$split = trimmed.split(":"),
810
+ _trimmed$split2 = _slicedToArray(_trimmed$split, 2),
811
+ h = _trimmed$split2[0],
812
+ m = _trimmed$split2[1];
813
+ return Number(h || 0) + Number(m || 0) / 60;
814
+ }
815
+ return Number(trimmed) || 0;
816
+ }, [value]);
817
+ var handleSubmit = (0, _react.useCallback)(function () {
818
+ var _user$name, _jobType$name;
819
+ onSubmit({
820
+ date,
821
+ userId,
822
+ userName: (_user$name = user === null || user === void 0 ? void 0 : user.name) !== null && _user$name !== void 0 ? _user$name : "",
823
+ jobType: (_jobType$name = jobType === null || jobType === void 0 ? void 0 : jobType.name) !== null && _jobType$name !== void 0 ? _jobType$name : "",
824
+ hours,
825
+ billable,
826
+ description
827
+ });
828
+ }, [billable, date, description, hours, jobType, onSubmit, user, userId]);
829
+ return /*#__PURE__*/_react.default.createElement(_Modal.Modal, {
830
+ open: open,
831
+ onClose: onClose
832
+ }, /*#__PURE__*/_react.default.createElement(_Transitions.SlideFromTop, {
833
+ in: open
834
+ }, /*#__PURE__*/_react.default.createElement(StyledTimeRecordPaper, {
835
+ role: "dialog",
836
+ "aria-label": "Add time record"
837
+ }, /*#__PURE__*/_react.default.createElement("div", {
838
+ className: "trd-header"
839
+ }, /*#__PURE__*/_react.default.createElement("span", {
840
+ className: "trd-title"
841
+ }, taskName), /*#__PURE__*/_react.default.createElement("span", {
842
+ className: "trd-date"
843
+ }, /*#__PURE__*/_react.default.createElement(_DatePicker.DatePicker, {
844
+ mode: "daily",
845
+ required: true,
846
+ firstDayOfWeek: 1,
847
+ position: "bottom-end",
848
+ selected: {
849
+ from: date,
850
+ to: date
851
+ },
852
+ onSave: function onSave(range) {
853
+ return range !== null && range !== void 0 && range.from ? setDate(Number(range.from)) : undefined;
854
+ },
855
+ target: /*#__PURE__*/_react.default.createElement(_SelectTrigger.SelectTrigger, null, formatDateRange(date, date))
856
+ }))), /*#__PURE__*/_react.default.createElement("div", {
857
+ className: "trd-divider"
858
+ }), /*#__PURE__*/_react.default.createElement("div", {
859
+ className: "trd-body"
860
+ }, /*#__PURE__*/_react.default.createElement("div", {
861
+ className: "trd-form"
862
+ }, /*#__PURE__*/_react.default.createElement("div", {
863
+ className: "trd-fields"
864
+ }, /*#__PURE__*/_react.default.createElement("span", {
865
+ className: "trd-hours"
866
+ }, /*#__PURE__*/_react.default.createElement(_Input.InputHours, {
867
+ autoFocus: true,
868
+ allowEmptyValue: true,
869
+ size: "biggest",
870
+ placeholder: "00:00",
871
+ value: value,
872
+ onChange: setValue
873
+ })), /*#__PURE__*/_react.default.createElement("span", {
874
+ className: "trd-field"
875
+ }, /*#__PURE__*/_react.default.createElement(_Label.Label, {
876
+ size: "small"
877
+ }, "User"), /*#__PURE__*/_react.default.createElement(_Select.Select, {
878
+ options: users,
879
+ selected: userId,
880
+ forceCloseMenu: true,
881
+ onChange: function onChange(next) {
882
+ return setUserId(String(next));
883
+ },
884
+ target: /*#__PURE__*/_react.default.createElement(_SelectTrigger.SelectTrigger, {
885
+ id: "trd-user"
886
+ }, user === null || user === void 0 ? void 0 : user.name)
887
+ })), /*#__PURE__*/_react.default.createElement("span", {
888
+ className: "trd-field"
889
+ }, /*#__PURE__*/_react.default.createElement(_Label.Label, {
890
+ size: "small"
891
+ }, "Job Type"), /*#__PURE__*/_react.default.createElement(_Select.Select, {
892
+ options: JOB_TYPES,
893
+ selected: jobTypeId,
894
+ forceCloseMenu: true,
895
+ onChange: function onChange(next) {
896
+ return setJobTypeId(String(next));
897
+ },
898
+ target: /*#__PURE__*/_react.default.createElement(_SelectTrigger.SelectTrigger, {
899
+ id: "trd-job-type"
900
+ }, jobType === null || jobType === void 0 ? void 0 : jobType.name)
901
+ })), /*#__PURE__*/_react.default.createElement("span", {
902
+ className: "trd-billable"
903
+ }, /*#__PURE__*/_react.default.createElement(_Checkbox.Checkbox, {
904
+ id: "trd-billable",
905
+ checked: billable,
906
+ onChange: function onChange() {
907
+ return setBillable(function (prev) {
908
+ return !prev;
909
+ });
910
+ }
911
+ }), /*#__PURE__*/_react.default.createElement(_Label.Label, {
912
+ htmlFor: "trd-billable",
913
+ weight: "regular"
914
+ }, "Billable"))), /*#__PURE__*/_react.default.createElement("button", {
915
+ type: "button",
916
+ className: showDescription ? "trd-description-trigger" : "trd-description-trigger collapsed",
917
+ onClick: function onClick() {
918
+ return setShowDescription(function (prev) {
919
+ return !prev;
920
+ });
921
+ }
922
+ }, /*#__PURE__*/_react.default.createElement(_Icons.CollapseExpandSingleIcon, null), /*#__PURE__*/_react.default.createElement("span", null, "Description")), showDescription ? /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_Textarea.Textarea, {
923
+ className: "trd-textarea",
924
+ value: description,
925
+ onChange: function onChange(event) {
926
+ return setDescription(event.target.value);
927
+ }
928
+ })) : null, /*#__PURE__*/_react.default.createElement("div", {
929
+ className: "trd-actions"
930
+ }, /*#__PURE__*/_react.default.createElement(_Button.Button, {
931
+ variant: "primary",
932
+ disabled: hours <= 0,
933
+ onClick: handleSubmit
934
+ }, "Add Time Record"), /*#__PURE__*/_react.default.createElement(_Button.Button, {
935
+ variant: "secondary",
936
+ onClick: onClose
937
+ }, "Cancel"))), total > 0 ? /*#__PURE__*/_react.default.createElement("button", {
938
+ type: "button",
939
+ className: showRecords ? "trd-total" : "trd-total collapsed",
940
+ onClick: function onClick() {
941
+ return setShowRecords(function (prev) {
942
+ return !prev;
943
+ });
944
+ }
945
+ }, /*#__PURE__*/_react.default.createElement(_Icons.CollapseExpandSingleIcon, null), /*#__PURE__*/_react.default.createElement(_Typography.Header3, {
946
+ color: "theme-secondary",
947
+ tabularNums: true
948
+ }, "Total: ", (0, _utils.formatHours)(total, false, true), "h")) : null), showRecords && records.length > 0 ? /*#__PURE__*/_react.default.createElement("div", {
949
+ className: "trd-records"
950
+ }, records.map(function (record) {
951
+ return /*#__PURE__*/_react.default.createElement("div", {
952
+ key: record.id,
953
+ className: "trd-record"
954
+ }, /*#__PURE__*/_react.default.createElement("span", {
955
+ className: "trd-record-left"
956
+ }, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
957
+ weight: "bold",
958
+ color: "secondary"
959
+ }, formatDateRange(record.date, record.date)), /*#__PURE__*/_react.default.createElement(_Typography.Body2, null, record.userName), /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
960
+ color: "secondary"
961
+ }, record.jobType)), /*#__PURE__*/_react.default.createElement(_Typography.Body2, {
962
+ weight: "bold",
963
+ tabularNums: true
964
+ }, (0, _utils.formatHours)(record.hours), "h"));
965
+ })) : null)));
966
+ };
967
+ //# sourceMappingURL=columns.js.map