@lv-x-software-house/x_view 1.2.5-dev.37 → 1.2.5-dev.38
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.
- package/dist/index.js +335 -13
- package/dist/index.mjs +339 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2851,7 +2851,7 @@ var userActionHandlers = {
|
|
|
2851
2851
|
}
|
|
2852
2852
|
},
|
|
2853
2853
|
handleSaveNodeDetails: async (context, updatedNode, keepOpen = false) => {
|
|
2854
|
-
var _a;
|
|
2854
|
+
var _a, _b, _c;
|
|
2855
2855
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2856
2856
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2857
2857
|
const {
|
|
@@ -2872,15 +2872,66 @@ var userActionHandlers = {
|
|
|
2872
2872
|
const { parentFileId, ownerId } = parentInfo;
|
|
2873
2873
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
2874
2874
|
const nodeIndex = specificParentData.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2875
|
-
if (nodeIndex
|
|
2876
|
-
specificParentData.nodes[nodeIndex] = { ...nodeToSave };
|
|
2877
|
-
} else {
|
|
2875
|
+
if (nodeIndex === -1) {
|
|
2878
2876
|
console.error("Node n\xE3o encontrado nos dados do parent para atualiza\xE7\xE3o:", nodeToSave.id);
|
|
2879
2877
|
alert("Erro interno: Node n\xE3o encontrado para salvar.");
|
|
2880
2878
|
return;
|
|
2881
2879
|
}
|
|
2880
|
+
const oldNode = specificParentData.nodes[nodeIndex];
|
|
2881
|
+
const isNewDone = oldNode.status !== "Done" && nodeToSave.status === "Done";
|
|
2882
|
+
specificParentData.nodes[nodeIndex] = { ...nodeToSave };
|
|
2883
|
+
if (isNewDone && nodeToSave.is_quest && ((_a = nodeToSave.recurrence_config) == null ? void 0 : _a.enabled)) {
|
|
2884
|
+
const nextDateObj = calculateNextRecurrenceDate(nodeToSave.recurrence_config);
|
|
2885
|
+
if (nextDateObj) {
|
|
2886
|
+
const currentCounter = sceneDataRef.current.quest_counter || 1;
|
|
2887
|
+
const nextCounter = currentCounter + 1;
|
|
2888
|
+
sceneDataRef.current.quest_counter = nextCounter;
|
|
2889
|
+
let nextName = nodeToSave.raw_title || nodeToSave.name;
|
|
2890
|
+
const prefixParts = (nodeToSave.name || "").split(" - \xBB ");
|
|
2891
|
+
if (prefixParts.length > 1) {
|
|
2892
|
+
const prefixBase = prefixParts[0].split(" - ")[0];
|
|
2893
|
+
nextName = `${prefixBase} - ${nextCounter} - \xBB ${nodeToSave.raw_title || prefixParts[1]}`;
|
|
2894
|
+
}
|
|
2895
|
+
const nextRecurrenceConfig = { ...nodeToSave.recurrence_config };
|
|
2896
|
+
if (nextRecurrenceConfig.type === "custom") {
|
|
2897
|
+
nextRecurrenceConfig.custom_date = "";
|
|
2898
|
+
}
|
|
2899
|
+
const nextQuestNode = {
|
|
2900
|
+
...JSON.parse(JSON.stringify(nodeToSave)),
|
|
2901
|
+
// Deep copy properties
|
|
2902
|
+
id: import_short_uuid.default.generate(),
|
|
2903
|
+
name: nextName,
|
|
2904
|
+
status: "Backlog",
|
|
2905
|
+
color: "#64748b",
|
|
2906
|
+
// QUEST_STATUS_COLORS["Backlog"]
|
|
2907
|
+
assignee_id: nodeToSave.recurrence_config.next_assignee_id || "",
|
|
2908
|
+
Date: nextDateObj,
|
|
2909
|
+
timeline: [{
|
|
2910
|
+
id: import_short_uuid.default.generate(),
|
|
2911
|
+
type: "status_changed",
|
|
2912
|
+
timestamp: Date.now(),
|
|
2913
|
+
actorId: "system",
|
|
2914
|
+
description: `Quest criada automaticamente via recorr\xEAncia a partir da quest #${nodeToSave.id}`,
|
|
2915
|
+
links: [],
|
|
2916
|
+
images: [],
|
|
2917
|
+
metadata: { status: "Backlog" }
|
|
2918
|
+
}],
|
|
2919
|
+
version_node: {
|
|
2920
|
+
is_version: true,
|
|
2921
|
+
parent_node: ((_b = nodeToSave.version_node) == null ? void 0 : _b.parent_node) || nodeToSave.id
|
|
2922
|
+
},
|
|
2923
|
+
recurrence_config: nextRecurrenceConfig
|
|
2924
|
+
};
|
|
2925
|
+
specificParentData.nodes.push(nextQuestNode);
|
|
2926
|
+
if (stateRef.current.nodeObjects[String(nodeToSave.id)]) {
|
|
2927
|
+
const pos = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
|
|
2928
|
+
pos.x += 12;
|
|
2929
|
+
addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2882
2933
|
try {
|
|
2883
|
-
const isView = ((
|
|
2934
|
+
const isView = ((_c = context.viewType) == null ? void 0 : _c.toLowerCase()) === "view";
|
|
2884
2935
|
if (isView && parentFileId === context.sceneConfigId) {
|
|
2885
2936
|
const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2886
2937
|
if (visualNodeIndex > -1) {
|
|
@@ -3736,10 +3787,44 @@ function createTimelineEntry(actorId, description, type = "comment", extras = {}
|
|
|
3736
3787
|
id: img.id || v4_default(),
|
|
3737
3788
|
name: img.name || "",
|
|
3738
3789
|
value: img.value || ""
|
|
3739
|
-
}))
|
|
3740
|
-
metadata
|
|
3790
|
+
}))
|
|
3741
3791
|
};
|
|
3742
3792
|
}
|
|
3793
|
+
function calculateNextRecurrenceDate(config) {
|
|
3794
|
+
if (!config || !config.enabled) return null;
|
|
3795
|
+
const now = /* @__PURE__ */ new Date();
|
|
3796
|
+
let nextDate = new Date(now);
|
|
3797
|
+
switch (config.type) {
|
|
3798
|
+
case "daily":
|
|
3799
|
+
nextDate.setDate(now.getDate() + 1);
|
|
3800
|
+
break;
|
|
3801
|
+
case "weekly":
|
|
3802
|
+
const targetDay = parseInt(config.day_of_week, 10);
|
|
3803
|
+
const currentDay = now.getDay();
|
|
3804
|
+
let daysUntilNext = targetDay - currentDay;
|
|
3805
|
+
if (daysUntilNext <= 0) daysUntilNext += 7;
|
|
3806
|
+
nextDate.setDate(now.getDate() + daysUntilNext);
|
|
3807
|
+
break;
|
|
3808
|
+
case "custom":
|
|
3809
|
+
if (config.custom_date) {
|
|
3810
|
+
const parts = config.custom_date.split("/");
|
|
3811
|
+
if (parts.length === 3) {
|
|
3812
|
+
nextDate = new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0], 10));
|
|
3813
|
+
} else {
|
|
3814
|
+
return null;
|
|
3815
|
+
}
|
|
3816
|
+
} else {
|
|
3817
|
+
return null;
|
|
3818
|
+
}
|
|
3819
|
+
break;
|
|
3820
|
+
default:
|
|
3821
|
+
return null;
|
|
3822
|
+
}
|
|
3823
|
+
const d = String(nextDate.getDate()).padStart(2, "0");
|
|
3824
|
+
const m = String(nextDate.getMonth() + 1).padStart(2, "0");
|
|
3825
|
+
const y = nextDate.getFullYear();
|
|
3826
|
+
return { date: `${d}/${m}/${y}` };
|
|
3827
|
+
}
|
|
3743
3828
|
|
|
3744
3829
|
// src/components/CustomPropertyDisplay.jsx
|
|
3745
3830
|
var import_react4 = __toESM(require("react"));
|
|
@@ -8866,7 +8951,15 @@ function InSceneQuestForm({
|
|
|
8866
8951
|
const [size, setSize] = (0, import_react17.useState)("medium");
|
|
8867
8952
|
const [intensity, setIntensity] = (0, import_react17.useState)(0);
|
|
8868
8953
|
const [description, setDescription] = (0, import_react17.useState)("");
|
|
8954
|
+
const [recurrenceConfig, setRecurrenceConfig] = (0, import_react17.useState)({
|
|
8955
|
+
enabled: false,
|
|
8956
|
+
type: "daily",
|
|
8957
|
+
day_of_week: 1,
|
|
8958
|
+
custom_date: "",
|
|
8959
|
+
next_assignee_id: ""
|
|
8960
|
+
});
|
|
8869
8961
|
const [reviewStack, setReviewStack] = (0, import_react17.useState)([]);
|
|
8962
|
+
const [questDate, setQuestDate] = (0, import_react17.useState)(null);
|
|
8870
8963
|
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react17.useState)(false);
|
|
8871
8964
|
const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react17.useState)(false);
|
|
8872
8965
|
const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react17.useState)("");
|
|
@@ -8938,6 +9031,8 @@ function InSceneQuestForm({
|
|
|
8938
9031
|
textureImageUrl: null,
|
|
8939
9032
|
reviewStack,
|
|
8940
9033
|
timeline: initialTimeline,
|
|
9034
|
+
Date: questDate,
|
|
9035
|
+
recurrence_config: recurrenceConfig,
|
|
8941
9036
|
...additionalData
|
|
8942
9037
|
});
|
|
8943
9038
|
};
|
|
@@ -9104,7 +9199,139 @@ function InSceneQuestForm({
|
|
|
9104
9199
|
)), viewMembers.filter((member) => {
|
|
9105
9200
|
const search = assigneeSearchQuery.toLowerCase();
|
|
9106
9201
|
return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
|
|
9107
|
-
}).length === 0 && assigneeSearchQuery && /* @__PURE__ */ import_react17.default.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "
|
|
9202
|
+
}).length === 0 && assigneeSearchQuery && /* @__PURE__ */ import_react17.default.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5 mt-2" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-xs text-slate-300 font-medium uppercase tracking-wider" }, "Prazo / Data"), !questDate && /* @__PURE__ */ import_react17.default.createElement(
|
|
9203
|
+
"button",
|
|
9204
|
+
{
|
|
9205
|
+
type: "button",
|
|
9206
|
+
onClick: () => setQuestDate({ type: "Data", value: "" }),
|
|
9207
|
+
className: "text-[10px] text-indigo-400 hover:text-indigo-300 font-bold uppercase transition-colors"
|
|
9208
|
+
},
|
|
9209
|
+
"+ Adicionar"
|
|
9210
|
+
)), questDate && /* @__PURE__ */ import_react17.default.createElement("div", { className: "p-3 bg-slate-900/60 rounded-xl border border-white/10 space-y-3 relative group" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
9211
|
+
"button",
|
|
9212
|
+
{
|
|
9213
|
+
type: "button",
|
|
9214
|
+
onClick: () => setQuestDate(null),
|
|
9215
|
+
className: "absolute top-2 right-2 w-6 h-6 grid place-items-center rounded-full bg-red-500/10 text-red-400 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
9216
|
+
title: "Remover data"
|
|
9217
|
+
},
|
|
9218
|
+
/* @__PURE__ */ import_react17.default.createElement(import_fi15.FiX, { size: 12 })
|
|
9219
|
+
), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-1 rounded-lg bg-slate-800/50 p-1" }, ["Data", "Ano", "Date Interval"].map((t) => /* @__PURE__ */ import_react17.default.createElement(
|
|
9220
|
+
"button",
|
|
9221
|
+
{
|
|
9222
|
+
key: t,
|
|
9223
|
+
type: "button",
|
|
9224
|
+
onClick: () => {
|
|
9225
|
+
const newDate = { type: t };
|
|
9226
|
+
if (t === "Date Interval") {
|
|
9227
|
+
newDate.start = "";
|
|
9228
|
+
newDate.end = "";
|
|
9229
|
+
} else {
|
|
9230
|
+
newDate.value = "";
|
|
9231
|
+
}
|
|
9232
|
+
setQuestDate(newDate);
|
|
9233
|
+
},
|
|
9234
|
+
className: `flex-1 text-[10px] px-2 py-1.5 rounded-md transition-colors ${questDate.type === t ? "bg-indigo-600 text-white font-semibold shadow" : "text-slate-400 hover:bg-slate-700/50"}`
|
|
9235
|
+
},
|
|
9236
|
+
t === "Date Interval" ? "Intervalo" : t
|
|
9237
|
+
))), questDate.type === "Data" && /* @__PURE__ */ import_react17.default.createElement(
|
|
9238
|
+
"input",
|
|
9239
|
+
{
|
|
9240
|
+
type: "text",
|
|
9241
|
+
placeholder: "DD/MM/AAAA",
|
|
9242
|
+
value: questDate.value || "",
|
|
9243
|
+
onChange: (e) => {
|
|
9244
|
+
const rawValue = e.target.value;
|
|
9245
|
+
const digits = rawValue.replace(/\D/g, "");
|
|
9246
|
+
const len = digits.length;
|
|
9247
|
+
let formattedValue = digits;
|
|
9248
|
+
if (len > 2 && len <= 4)
|
|
9249
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2)}`;
|
|
9250
|
+
else if (len > 4)
|
|
9251
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4, 8)}`;
|
|
9252
|
+
setQuestDate({ ...questDate, value: formattedValue });
|
|
9253
|
+
},
|
|
9254
|
+
maxLength: "10",
|
|
9255
|
+
className: "w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60"
|
|
9256
|
+
}
|
|
9257
|
+
), questDate.type === "Ano" && /* @__PURE__ */ import_react17.default.createElement(
|
|
9258
|
+
"input",
|
|
9259
|
+
{
|
|
9260
|
+
type: "number",
|
|
9261
|
+
placeholder: "AAAA",
|
|
9262
|
+
value: questDate.value || "",
|
|
9263
|
+
onChange: (e) => setQuestDate({ ...questDate, value: e.target.value }),
|
|
9264
|
+
className: "w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
9265
|
+
}
|
|
9266
|
+
), questDate.type === "Date Interval" && /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
9267
|
+
"input",
|
|
9268
|
+
{
|
|
9269
|
+
type: "number",
|
|
9270
|
+
placeholder: "In\xEDcio (Ano)",
|
|
9271
|
+
value: questDate.start || "",
|
|
9272
|
+
onChange: (e) => setQuestDate({ ...questDate, start: e.target.value }),
|
|
9273
|
+
className: "flex-1 bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
9274
|
+
}
|
|
9275
|
+
), /* @__PURE__ */ import_react17.default.createElement("span", { className: "text-slate-500" }, "-"), /* @__PURE__ */ import_react17.default.createElement(
|
|
9276
|
+
"input",
|
|
9277
|
+
{
|
|
9278
|
+
type: "number",
|
|
9279
|
+
placeholder: "Fim (Ano)",
|
|
9280
|
+
value: questDate.end || "",
|
|
9281
|
+
onChange: (e) => setQuestDate({ ...questDate, end: e.target.value }),
|
|
9282
|
+
className: "flex-1 bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
9283
|
+
}
|
|
9284
|
+
)))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "pt-4 border-t border-white/5 mt-2" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center justify-between mb-3" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiRepeat, { className: `w-3.5 h-3.5 ${recurrenceConfig.enabled ? "text-indigo-400" : "text-slate-500"}` }), /* @__PURE__ */ import_react17.default.createElement("span", { className: "text-xs text-slate-300 font-medium uppercase tracking-wider" }, "Recorr\xEAncia")), /* @__PURE__ */ import_react17.default.createElement(
|
|
9285
|
+
"button",
|
|
9286
|
+
{
|
|
9287
|
+
type: "button",
|
|
9288
|
+
onClick: () => setRecurrenceConfig((prev) => ({ ...prev, enabled: !prev.enabled })),
|
|
9289
|
+
className: `relative inline-flex h-5 w-9 items-center rounded-full transition-colors focus:outline-none ${recurrenceConfig.enabled ? "bg-indigo-600" : "bg-slate-700"} cursor-pointer`
|
|
9290
|
+
},
|
|
9291
|
+
/* @__PURE__ */ import_react17.default.createElement("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform ${recurrenceConfig.enabled ? "translate-x-4.5" : "translate-x-1"}` })
|
|
9292
|
+
)), recurrenceConfig.enabled && /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-4 p-3 rounded-xl bg-white/5 border border-white/5 animate-in fade-in slide-in-from-top-1" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "grid grid-cols-2 gap-3" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Tipo"), /* @__PURE__ */ import_react17.default.createElement(
|
|
9293
|
+
"select",
|
|
9294
|
+
{
|
|
9295
|
+
value: recurrenceConfig.type,
|
|
9296
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, type: e.target.value })),
|
|
9297
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg px-2 py-1.5 text-xs text-slate-200 focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9298
|
+
},
|
|
9299
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "daily" }, "Di\xE1ria"),
|
|
9300
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "weekly" }, "Semanal"),
|
|
9301
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "custom" }, "Data Espec\xEDfica")
|
|
9302
|
+
)), recurrenceConfig.type === "weekly" && /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Dia da Semana"), /* @__PURE__ */ import_react17.default.createElement(
|
|
9303
|
+
"select",
|
|
9304
|
+
{
|
|
9305
|
+
value: recurrenceConfig.day_of_week,
|
|
9306
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, day_of_week: parseInt(e.target.value, 10) })),
|
|
9307
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg px-2 py-1.5 text-xs text-slate-200 focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9308
|
+
},
|
|
9309
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 1 }, "Segunda-feira"),
|
|
9310
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 2 }, "Ter\xE7a-feira"),
|
|
9311
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 3 }, "Quarta-feira"),
|
|
9312
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 4 }, "Quinta-feira"),
|
|
9313
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 5 }, "Sexta-feira"),
|
|
9314
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 6 }, "S\xE1bado"),
|
|
9315
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 0 }, "Domingo")
|
|
9316
|
+
)), recurrenceConfig.type === "custom" && /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Pr\xF3xima Data"), /* @__PURE__ */ import_react17.default.createElement(
|
|
9317
|
+
"input",
|
|
9318
|
+
{
|
|
9319
|
+
type: "text",
|
|
9320
|
+
placeholder: "DD/MM/AAAA",
|
|
9321
|
+
value: recurrenceConfig.custom_date,
|
|
9322
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, custom_date: e.target.value })),
|
|
9323
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg px-2 py-1.5 text-xs text-slate-200 focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9324
|
+
}
|
|
9325
|
+
))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Pr\xF3ximo Respons\xE1vel"), /* @__PURE__ */ import_react17.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
9326
|
+
"select",
|
|
9327
|
+
{
|
|
9328
|
+
value: recurrenceConfig.next_assignee_id,
|
|
9329
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, next_assignee_id: e.target.value })),
|
|
9330
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg pl-8 pr-2 py-1.5 text-xs text-slate-200 appearance-none focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9331
|
+
},
|
|
9332
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "" }, "Sem respons\xE1vel"),
|
|
9333
|
+
viewMembers.map((member) => /* @__PURE__ */ import_react17.default.createElement("option", { key: member.id, value: member.id }, member.name || member.email))
|
|
9334
|
+
), /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiUser, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-slate-500" }), /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiChevronDown, { className: "absolute right-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-slate-500 pointer-events-none" }))))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
9108
9335
|
QuestReviewStackEditor,
|
|
9109
9336
|
{
|
|
9110
9337
|
reviewStack,
|
|
@@ -9889,12 +10116,20 @@ function QuestDetailsPanel({
|
|
|
9889
10116
|
const [isSaving, setIsSaving] = (0, import_react20.useState)(false);
|
|
9890
10117
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react20.useState)(false);
|
|
9891
10118
|
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react20.useState)(false);
|
|
10119
|
+
const [questDate, setQuestDate] = (0, import_react20.useState)((node == null ? void 0 : node.Date) || null);
|
|
9892
10120
|
const [noteText, setNoteText] = (0, import_react20.useState)("");
|
|
9893
10121
|
const [noteLinks, setNoteLinks] = (0, import_react20.useState)([]);
|
|
9894
10122
|
const [noteImages, setNoteImages] = (0, import_react20.useState)([]);
|
|
9895
10123
|
const [isNoteFormOpen, setIsNoteFormOpen] = (0, import_react20.useState)(false);
|
|
9896
10124
|
const [editingEntryId, setEditingEntryId] = (0, import_react20.useState)(null);
|
|
9897
10125
|
const [editingEntryLabel, setEditingEntryLabel] = (0, import_react20.useState)("");
|
|
10126
|
+
const [recurrenceConfig, setRecurrenceConfig] = (0, import_react20.useState)((node == null ? void 0 : node.recurrence_config) || {
|
|
10127
|
+
enabled: false,
|
|
10128
|
+
type: "daily",
|
|
10129
|
+
day_of_week: 1,
|
|
10130
|
+
custom_date: "",
|
|
10131
|
+
next_assignee_id: ""
|
|
10132
|
+
});
|
|
9898
10133
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9899
10134
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
9900
10135
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -9930,6 +10165,14 @@ function QuestDetailsPanel({
|
|
|
9930
10165
|
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
9931
10166
|
setReviewStack((node == null ? void 0 : node.reviewStack) || []);
|
|
9932
10167
|
setTimeline((node == null ? void 0 : node.timeline) || []);
|
|
10168
|
+
setQuestDate((node == null ? void 0 : node.Date) || null);
|
|
10169
|
+
setRecurrenceConfig((node == null ? void 0 : node.recurrence_config) || {
|
|
10170
|
+
enabled: false,
|
|
10171
|
+
type: "daily",
|
|
10172
|
+
day_of_week: 1,
|
|
10173
|
+
custom_date: "",
|
|
10174
|
+
next_assignee_id: ""
|
|
10175
|
+
});
|
|
9933
10176
|
setHasUnsavedChanges(false);
|
|
9934
10177
|
}
|
|
9935
10178
|
}, [node]);
|
|
@@ -10025,6 +10268,7 @@ function QuestDetailsPanel({
|
|
|
10025
10268
|
setIsSaving(false);
|
|
10026
10269
|
}
|
|
10027
10270
|
};
|
|
10271
|
+
const filteredCustomProps = customProps.filter((p) => p.key !== "Date" && p.key !== "Data");
|
|
10028
10272
|
const handleAddTimelineNote = async () => {
|
|
10029
10273
|
if (!noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving) return;
|
|
10030
10274
|
setIsSaving(true);
|
|
@@ -10181,6 +10425,7 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10181
10425
|
const currentTimeline = overrides.timeline !== void 0 ? overrides.timeline : timeline;
|
|
10182
10426
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
10183
10427
|
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
10428
|
+
const currentRecurrenceConfig = overrides.recurrenceConfig !== void 0 ? overrides.recurrenceConfig : recurrenceConfig;
|
|
10184
10429
|
if (!keepOpen && !hasUnsavedChanges) {
|
|
10185
10430
|
onClose();
|
|
10186
10431
|
return;
|
|
@@ -10204,11 +10449,13 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10204
10449
|
status: currentStatus,
|
|
10205
10450
|
assignee_id: currentAssigneeId || null,
|
|
10206
10451
|
size,
|
|
10207
|
-
description: currentDescription,
|
|
10452
|
+
description: currentDescription.trim(),
|
|
10208
10453
|
description_sections: processedSections,
|
|
10454
|
+
intensity,
|
|
10455
|
+
recurrence_config: currentRecurrenceConfig,
|
|
10456
|
+
Date: questDate,
|
|
10209
10457
|
useImageAsTexture: false,
|
|
10210
10458
|
textureImageUrl: null,
|
|
10211
|
-
intensity,
|
|
10212
10459
|
is_quest: true,
|
|
10213
10460
|
reviewStack: currentReviewStack,
|
|
10214
10461
|
timeline: currentTimeline,
|
|
@@ -12570,7 +12817,7 @@ function XViewScene({
|
|
|
12570
12817
|
}
|
|
12571
12818
|
}
|
|
12572
12819
|
Object.values(nodeObjects).forEach((mesh) => {
|
|
12573
|
-
const oldLabel = mesh.getObjectByName("timelineLabel");
|
|
12820
|
+
const oldLabel = mesh.getObjectByName("timelineLabel") || mesh.getObjectByName("questDateLabel");
|
|
12574
12821
|
if (oldLabel) {
|
|
12575
12822
|
mesh.remove(oldLabel);
|
|
12576
12823
|
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
@@ -13003,8 +13250,16 @@ function XViewScene({
|
|
|
13003
13250
|
);
|
|
13004
13251
|
const handleActivateQuestLens = (0, import_react28.useCallback)(({ assigneeId, status: status2 }) => {
|
|
13005
13252
|
var _a2;
|
|
13006
|
-
const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
|
|
13253
|
+
const { nodeObjects, tweenGroup, graphGroup, timelineIntervalsGroup } = stateRef.current;
|
|
13007
13254
|
if (!nodeObjects || !tweenGroup || !graphGroup) return;
|
|
13255
|
+
Object.values(nodeObjects).forEach((mesh) => {
|
|
13256
|
+
const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
|
|
13257
|
+
if (oldLabel) {
|
|
13258
|
+
mesh.remove(oldLabel);
|
|
13259
|
+
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
13260
|
+
oldLabel.material.dispose();
|
|
13261
|
+
}
|
|
13262
|
+
});
|
|
13008
13263
|
const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
|
|
13009
13264
|
const filteredQuests = allQuests.filter((q) => {
|
|
13010
13265
|
const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
|
|
@@ -13026,6 +13281,60 @@ function XViewScene({
|
|
|
13026
13281
|
questsByStatus[q.status].push(q);
|
|
13027
13282
|
}
|
|
13028
13283
|
});
|
|
13284
|
+
const parseDate = (str) => {
|
|
13285
|
+
if (!str) return null;
|
|
13286
|
+
const parts = str.split("/");
|
|
13287
|
+
if (parts.length === 3) {
|
|
13288
|
+
const day = parseInt(parts[0], 10);
|
|
13289
|
+
const month = parseInt(parts[1], 10) - 1;
|
|
13290
|
+
const year = parseInt(parts[2], 10);
|
|
13291
|
+
if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
|
|
13292
|
+
return new Date(year, month, day);
|
|
13293
|
+
}
|
|
13294
|
+
}
|
|
13295
|
+
return null;
|
|
13296
|
+
};
|
|
13297
|
+
const timePoints = /* @__PURE__ */ new Set();
|
|
13298
|
+
const questTimeInfos = /* @__PURE__ */ new Map();
|
|
13299
|
+
filteredQuests.forEach((q) => {
|
|
13300
|
+
const dateProp = q.Date;
|
|
13301
|
+
let info = { isUndated: true, label: "" };
|
|
13302
|
+
if (dateProp) {
|
|
13303
|
+
if (dateProp.date) {
|
|
13304
|
+
const d = parseDate(dateProp.date);
|
|
13305
|
+
if (d) {
|
|
13306
|
+
info = { startDate: d, endDate: d, label: dateProp.date, isUndated: false };
|
|
13307
|
+
timePoints.add(d.getTime());
|
|
13308
|
+
}
|
|
13309
|
+
} else if (dateProp.year) {
|
|
13310
|
+
const y = parseInt(dateProp.year, 10);
|
|
13311
|
+
if (!isNaN(y)) {
|
|
13312
|
+
const d = new Date(y, 0, 1);
|
|
13313
|
+
info = { startDate: d, endDate: d, label: String(y), isUndated: false };
|
|
13314
|
+
timePoints.add(d.getTime());
|
|
13315
|
+
}
|
|
13316
|
+
} else if (dateProp.date_interval && dateProp.date_interval.start) {
|
|
13317
|
+
const sY = parseInt(dateProp.date_interval.start, 10);
|
|
13318
|
+
const eY = parseInt(dateProp.date_interval.end, 10) || sY;
|
|
13319
|
+
if (!isNaN(sY)) {
|
|
13320
|
+
const sd = new Date(sY, 0, 1);
|
|
13321
|
+
const ed = new Date(eY, 11, 31);
|
|
13322
|
+
info = { startDate: sd, endDate: ed, label: `${sY}-${eY}`, isUndated: false };
|
|
13323
|
+
timePoints.add(sd.getTime());
|
|
13324
|
+
timePoints.add(ed.getTime());
|
|
13325
|
+
}
|
|
13326
|
+
}
|
|
13327
|
+
}
|
|
13328
|
+
questTimeInfos.set(String(q.id), info);
|
|
13329
|
+
});
|
|
13330
|
+
const sortedTimePoints = Array.from(timePoints).sort((a, b) => a - b);
|
|
13331
|
+
const timeToYMap = /* @__PURE__ */ new Map();
|
|
13332
|
+
if (sortedTimePoints.length > 0) {
|
|
13333
|
+
const maxIdx = sortedTimePoints.length - 1;
|
|
13334
|
+
sortedTimePoints.forEach((t, i) => {
|
|
13335
|
+
timeToYMap.set(t, (i - maxIdx) * (QUEST_LENS_ROW_SPACING || 30));
|
|
13336
|
+
});
|
|
13337
|
+
}
|
|
13029
13338
|
const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
|
|
13030
13339
|
Object.keys(nodeObjects).forEach((id) => {
|
|
13031
13340
|
const mesh = nodeObjects[id];
|
|
@@ -13062,10 +13371,23 @@ function XViewScene({
|
|
|
13062
13371
|
if (!mesh) {
|
|
13063
13372
|
mesh = addOrUpdateNodeMesh(q, new THREE3.Vector3(colX, 150, 0), true);
|
|
13064
13373
|
}
|
|
13065
|
-
const
|
|
13374
|
+
const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
|
|
13375
|
+
let targetY;
|
|
13376
|
+
if (!timeInfo.isUndated) {
|
|
13377
|
+
targetY = timeToYMap.get(timeInfo.startDate.getTime());
|
|
13378
|
+
} else {
|
|
13379
|
+
const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
|
|
13380
|
+
targetY = -80 - rowIndex * (QUEST_LENS_ROW_SPACING || 30) - undatedOffset;
|
|
13381
|
+
}
|
|
13066
13382
|
const lensTween = new import_tween2.Tween(mesh.position).to({ x: colX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
|
|
13067
13383
|
tweenGroup.add(lensTween);
|
|
13068
13384
|
lensTween.start();
|
|
13385
|
+
if (!timeInfo.isUndated && timeInfo.label) {
|
|
13386
|
+
const dateSprite = createTextSprite(timeInfo.label, 36);
|
|
13387
|
+
dateSprite.name = "questDateLabel";
|
|
13388
|
+
dateSprite.position.set(0, 3.5, 0);
|
|
13389
|
+
mesh.add(dateSprite);
|
|
13390
|
+
}
|
|
13069
13391
|
if (mesh.userData.labelObject) {
|
|
13070
13392
|
const labelTargetPos = new THREE3.Vector3(colX, targetY, 0).add(
|
|
13071
13393
|
mesh.userData.labelOffset || new THREE3.Vector3(0, -2.5, 0)
|
package/dist/index.mjs
CHANGED
|
@@ -2812,7 +2812,7 @@ var userActionHandlers = {
|
|
|
2812
2812
|
}
|
|
2813
2813
|
},
|
|
2814
2814
|
handleSaveNodeDetails: async (context, updatedNode, keepOpen = false) => {
|
|
2815
|
-
var _a;
|
|
2815
|
+
var _a, _b, _c;
|
|
2816
2816
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2817
2817
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2818
2818
|
const {
|
|
@@ -2833,15 +2833,66 @@ var userActionHandlers = {
|
|
|
2833
2833
|
const { parentFileId, ownerId } = parentInfo;
|
|
2834
2834
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
2835
2835
|
const nodeIndex = specificParentData.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2836
|
-
if (nodeIndex
|
|
2837
|
-
specificParentData.nodes[nodeIndex] = { ...nodeToSave };
|
|
2838
|
-
} else {
|
|
2836
|
+
if (nodeIndex === -1) {
|
|
2839
2837
|
console.error("Node n\xE3o encontrado nos dados do parent para atualiza\xE7\xE3o:", nodeToSave.id);
|
|
2840
2838
|
alert("Erro interno: Node n\xE3o encontrado para salvar.");
|
|
2841
2839
|
return;
|
|
2842
2840
|
}
|
|
2841
|
+
const oldNode = specificParentData.nodes[nodeIndex];
|
|
2842
|
+
const isNewDone = oldNode.status !== "Done" && nodeToSave.status === "Done";
|
|
2843
|
+
specificParentData.nodes[nodeIndex] = { ...nodeToSave };
|
|
2844
|
+
if (isNewDone && nodeToSave.is_quest && ((_a = nodeToSave.recurrence_config) == null ? void 0 : _a.enabled)) {
|
|
2845
|
+
const nextDateObj = calculateNextRecurrenceDate(nodeToSave.recurrence_config);
|
|
2846
|
+
if (nextDateObj) {
|
|
2847
|
+
const currentCounter = sceneDataRef.current.quest_counter || 1;
|
|
2848
|
+
const nextCounter = currentCounter + 1;
|
|
2849
|
+
sceneDataRef.current.quest_counter = nextCounter;
|
|
2850
|
+
let nextName = nodeToSave.raw_title || nodeToSave.name;
|
|
2851
|
+
const prefixParts = (nodeToSave.name || "").split(" - \xBB ");
|
|
2852
|
+
if (prefixParts.length > 1) {
|
|
2853
|
+
const prefixBase = prefixParts[0].split(" - ")[0];
|
|
2854
|
+
nextName = `${prefixBase} - ${nextCounter} - \xBB ${nodeToSave.raw_title || prefixParts[1]}`;
|
|
2855
|
+
}
|
|
2856
|
+
const nextRecurrenceConfig = { ...nodeToSave.recurrence_config };
|
|
2857
|
+
if (nextRecurrenceConfig.type === "custom") {
|
|
2858
|
+
nextRecurrenceConfig.custom_date = "";
|
|
2859
|
+
}
|
|
2860
|
+
const nextQuestNode = {
|
|
2861
|
+
...JSON.parse(JSON.stringify(nodeToSave)),
|
|
2862
|
+
// Deep copy properties
|
|
2863
|
+
id: short.generate(),
|
|
2864
|
+
name: nextName,
|
|
2865
|
+
status: "Backlog",
|
|
2866
|
+
color: "#64748b",
|
|
2867
|
+
// QUEST_STATUS_COLORS["Backlog"]
|
|
2868
|
+
assignee_id: nodeToSave.recurrence_config.next_assignee_id || "",
|
|
2869
|
+
Date: nextDateObj,
|
|
2870
|
+
timeline: [{
|
|
2871
|
+
id: short.generate(),
|
|
2872
|
+
type: "status_changed",
|
|
2873
|
+
timestamp: Date.now(),
|
|
2874
|
+
actorId: "system",
|
|
2875
|
+
description: `Quest criada automaticamente via recorr\xEAncia a partir da quest #${nodeToSave.id}`,
|
|
2876
|
+
links: [],
|
|
2877
|
+
images: [],
|
|
2878
|
+
metadata: { status: "Backlog" }
|
|
2879
|
+
}],
|
|
2880
|
+
version_node: {
|
|
2881
|
+
is_version: true,
|
|
2882
|
+
parent_node: ((_b = nodeToSave.version_node) == null ? void 0 : _b.parent_node) || nodeToSave.id
|
|
2883
|
+
},
|
|
2884
|
+
recurrence_config: nextRecurrenceConfig
|
|
2885
|
+
};
|
|
2886
|
+
specificParentData.nodes.push(nextQuestNode);
|
|
2887
|
+
if (stateRef.current.nodeObjects[String(nodeToSave.id)]) {
|
|
2888
|
+
const pos = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
|
|
2889
|
+
pos.x += 12;
|
|
2890
|
+
addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2843
2894
|
try {
|
|
2844
|
-
const isView = ((
|
|
2895
|
+
const isView = ((_c = context.viewType) == null ? void 0 : _c.toLowerCase()) === "view";
|
|
2845
2896
|
if (isView && parentFileId === context.sceneConfigId) {
|
|
2846
2897
|
const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2847
2898
|
if (visualNodeIndex > -1) {
|
|
@@ -3697,10 +3748,44 @@ function createTimelineEntry(actorId, description, type = "comment", extras = {}
|
|
|
3697
3748
|
id: img.id || v4_default(),
|
|
3698
3749
|
name: img.name || "",
|
|
3699
3750
|
value: img.value || ""
|
|
3700
|
-
}))
|
|
3701
|
-
metadata
|
|
3751
|
+
}))
|
|
3702
3752
|
};
|
|
3703
3753
|
}
|
|
3754
|
+
function calculateNextRecurrenceDate(config) {
|
|
3755
|
+
if (!config || !config.enabled) return null;
|
|
3756
|
+
const now = /* @__PURE__ */ new Date();
|
|
3757
|
+
let nextDate = new Date(now);
|
|
3758
|
+
switch (config.type) {
|
|
3759
|
+
case "daily":
|
|
3760
|
+
nextDate.setDate(now.getDate() + 1);
|
|
3761
|
+
break;
|
|
3762
|
+
case "weekly":
|
|
3763
|
+
const targetDay = parseInt(config.day_of_week, 10);
|
|
3764
|
+
const currentDay = now.getDay();
|
|
3765
|
+
let daysUntilNext = targetDay - currentDay;
|
|
3766
|
+
if (daysUntilNext <= 0) daysUntilNext += 7;
|
|
3767
|
+
nextDate.setDate(now.getDate() + daysUntilNext);
|
|
3768
|
+
break;
|
|
3769
|
+
case "custom":
|
|
3770
|
+
if (config.custom_date) {
|
|
3771
|
+
const parts = config.custom_date.split("/");
|
|
3772
|
+
if (parts.length === 3) {
|
|
3773
|
+
nextDate = new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0], 10));
|
|
3774
|
+
} else {
|
|
3775
|
+
return null;
|
|
3776
|
+
}
|
|
3777
|
+
} else {
|
|
3778
|
+
return null;
|
|
3779
|
+
}
|
|
3780
|
+
break;
|
|
3781
|
+
default:
|
|
3782
|
+
return null;
|
|
3783
|
+
}
|
|
3784
|
+
const d = String(nextDate.getDate()).padStart(2, "0");
|
|
3785
|
+
const m = String(nextDate.getMonth() + 1).padStart(2, "0");
|
|
3786
|
+
const y = nextDate.getFullYear();
|
|
3787
|
+
return { date: `${d}/${m}/${y}` };
|
|
3788
|
+
}
|
|
3704
3789
|
|
|
3705
3790
|
// src/components/CustomPropertyDisplay.jsx
|
|
3706
3791
|
import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
@@ -8684,7 +8769,9 @@ import {
|
|
|
8684
8769
|
FiX as FiX5,
|
|
8685
8770
|
FiChevronDown as FiChevronDown6,
|
|
8686
8771
|
FiUser as FiUser2,
|
|
8687
|
-
FiSearch as FiSearch5
|
|
8772
|
+
FiSearch as FiSearch5,
|
|
8773
|
+
FiCalendar,
|
|
8774
|
+
FiRepeat
|
|
8688
8775
|
} from "react-icons/fi";
|
|
8689
8776
|
|
|
8690
8777
|
// src/components/QuestReviewStackEditor.jsx
|
|
@@ -8883,7 +8970,15 @@ function InSceneQuestForm({
|
|
|
8883
8970
|
const [size, setSize] = useState17("medium");
|
|
8884
8971
|
const [intensity, setIntensity] = useState17(0);
|
|
8885
8972
|
const [description, setDescription] = useState17("");
|
|
8973
|
+
const [recurrenceConfig, setRecurrenceConfig] = useState17({
|
|
8974
|
+
enabled: false,
|
|
8975
|
+
type: "daily",
|
|
8976
|
+
day_of_week: 1,
|
|
8977
|
+
custom_date: "",
|
|
8978
|
+
next_assignee_id: ""
|
|
8979
|
+
});
|
|
8886
8980
|
const [reviewStack, setReviewStack] = useState17([]);
|
|
8981
|
+
const [questDate, setQuestDate] = useState17(null);
|
|
8887
8982
|
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState17(false);
|
|
8888
8983
|
const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = useState17(false);
|
|
8889
8984
|
const [assigneeSearchQuery, setAssigneeSearchQuery] = useState17("");
|
|
@@ -8955,6 +9050,8 @@ function InSceneQuestForm({
|
|
|
8955
9050
|
textureImageUrl: null,
|
|
8956
9051
|
reviewStack,
|
|
8957
9052
|
timeline: initialTimeline,
|
|
9053
|
+
Date: questDate,
|
|
9054
|
+
recurrence_config: recurrenceConfig,
|
|
8958
9055
|
...additionalData
|
|
8959
9056
|
});
|
|
8960
9057
|
};
|
|
@@ -9121,7 +9218,139 @@ function InSceneQuestForm({
|
|
|
9121
9218
|
)), viewMembers.filter((member) => {
|
|
9122
9219
|
const search = assigneeSearchQuery.toLowerCase();
|
|
9123
9220
|
return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
|
|
9124
|
-
}).length === 0 && assigneeSearchQuery && /* @__PURE__ */ React16.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__PURE__ */ React16.createElement("div", { className: "
|
|
9221
|
+
}).length === 0 && assigneeSearchQuery && /* @__PURE__ */ React16.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5 mt-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300 font-medium uppercase tracking-wider" }, "Prazo / Data"), !questDate && /* @__PURE__ */ React16.createElement(
|
|
9222
|
+
"button",
|
|
9223
|
+
{
|
|
9224
|
+
type: "button",
|
|
9225
|
+
onClick: () => setQuestDate({ type: "Data", value: "" }),
|
|
9226
|
+
className: "text-[10px] text-indigo-400 hover:text-indigo-300 font-bold uppercase transition-colors"
|
|
9227
|
+
},
|
|
9228
|
+
"+ Adicionar"
|
|
9229
|
+
)), questDate && /* @__PURE__ */ React16.createElement("div", { className: "p-3 bg-slate-900/60 rounded-xl border border-white/10 space-y-3 relative group" }, /* @__PURE__ */ React16.createElement(
|
|
9230
|
+
"button",
|
|
9231
|
+
{
|
|
9232
|
+
type: "button",
|
|
9233
|
+
onClick: () => setQuestDate(null),
|
|
9234
|
+
className: "absolute top-2 right-2 w-6 h-6 grid place-items-center rounded-full bg-red-500/10 text-red-400 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
9235
|
+
title: "Remover data"
|
|
9236
|
+
},
|
|
9237
|
+
/* @__PURE__ */ React16.createElement(FiX5, { size: 12 })
|
|
9238
|
+
), /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-1 rounded-lg bg-slate-800/50 p-1" }, ["Data", "Ano", "Date Interval"].map((t) => /* @__PURE__ */ React16.createElement(
|
|
9239
|
+
"button",
|
|
9240
|
+
{
|
|
9241
|
+
key: t,
|
|
9242
|
+
type: "button",
|
|
9243
|
+
onClick: () => {
|
|
9244
|
+
const newDate = { type: t };
|
|
9245
|
+
if (t === "Date Interval") {
|
|
9246
|
+
newDate.start = "";
|
|
9247
|
+
newDate.end = "";
|
|
9248
|
+
} else {
|
|
9249
|
+
newDate.value = "";
|
|
9250
|
+
}
|
|
9251
|
+
setQuestDate(newDate);
|
|
9252
|
+
},
|
|
9253
|
+
className: `flex-1 text-[10px] px-2 py-1.5 rounded-md transition-colors ${questDate.type === t ? "bg-indigo-600 text-white font-semibold shadow" : "text-slate-400 hover:bg-slate-700/50"}`
|
|
9254
|
+
},
|
|
9255
|
+
t === "Date Interval" ? "Intervalo" : t
|
|
9256
|
+
))), questDate.type === "Data" && /* @__PURE__ */ React16.createElement(
|
|
9257
|
+
"input",
|
|
9258
|
+
{
|
|
9259
|
+
type: "text",
|
|
9260
|
+
placeholder: "DD/MM/AAAA",
|
|
9261
|
+
value: questDate.value || "",
|
|
9262
|
+
onChange: (e) => {
|
|
9263
|
+
const rawValue = e.target.value;
|
|
9264
|
+
const digits = rawValue.replace(/\D/g, "");
|
|
9265
|
+
const len = digits.length;
|
|
9266
|
+
let formattedValue = digits;
|
|
9267
|
+
if (len > 2 && len <= 4)
|
|
9268
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2)}`;
|
|
9269
|
+
else if (len > 4)
|
|
9270
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4, 8)}`;
|
|
9271
|
+
setQuestDate({ ...questDate, value: formattedValue });
|
|
9272
|
+
},
|
|
9273
|
+
maxLength: "10",
|
|
9274
|
+
className: "w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60"
|
|
9275
|
+
}
|
|
9276
|
+
), questDate.type === "Ano" && /* @__PURE__ */ React16.createElement(
|
|
9277
|
+
"input",
|
|
9278
|
+
{
|
|
9279
|
+
type: "number",
|
|
9280
|
+
placeholder: "AAAA",
|
|
9281
|
+
value: questDate.value || "",
|
|
9282
|
+
onChange: (e) => setQuestDate({ ...questDate, value: e.target.value }),
|
|
9283
|
+
className: "w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
9284
|
+
}
|
|
9285
|
+
), questDate.type === "Date Interval" && /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(
|
|
9286
|
+
"input",
|
|
9287
|
+
{
|
|
9288
|
+
type: "number",
|
|
9289
|
+
placeholder: "In\xEDcio (Ano)",
|
|
9290
|
+
value: questDate.start || "",
|
|
9291
|
+
onChange: (e) => setQuestDate({ ...questDate, start: e.target.value }),
|
|
9292
|
+
className: "flex-1 bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
9293
|
+
}
|
|
9294
|
+
), /* @__PURE__ */ React16.createElement("span", { className: "text-slate-500" }, "-"), /* @__PURE__ */ React16.createElement(
|
|
9295
|
+
"input",
|
|
9296
|
+
{
|
|
9297
|
+
type: "number",
|
|
9298
|
+
placeholder: "Fim (Ano)",
|
|
9299
|
+
value: questDate.end || "",
|
|
9300
|
+
onChange: (e) => setQuestDate({ ...questDate, end: e.target.value }),
|
|
9301
|
+
className: "flex-1 bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
9302
|
+
}
|
|
9303
|
+
)))), /* @__PURE__ */ React16.createElement("div", { className: "pt-4 border-t border-white/5 mt-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between mb-3" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(FiRepeat, { className: `w-3.5 h-3.5 ${recurrenceConfig.enabled ? "text-indigo-400" : "text-slate-500"}` }), /* @__PURE__ */ React16.createElement("span", { className: "text-xs text-slate-300 font-medium uppercase tracking-wider" }, "Recorr\xEAncia")), /* @__PURE__ */ React16.createElement(
|
|
9304
|
+
"button",
|
|
9305
|
+
{
|
|
9306
|
+
type: "button",
|
|
9307
|
+
onClick: () => setRecurrenceConfig((prev) => ({ ...prev, enabled: !prev.enabled })),
|
|
9308
|
+
className: `relative inline-flex h-5 w-9 items-center rounded-full transition-colors focus:outline-none ${recurrenceConfig.enabled ? "bg-indigo-600" : "bg-slate-700"} cursor-pointer`
|
|
9309
|
+
},
|
|
9310
|
+
/* @__PURE__ */ React16.createElement("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform ${recurrenceConfig.enabled ? "translate-x-4.5" : "translate-x-1"}` })
|
|
9311
|
+
)), recurrenceConfig.enabled && /* @__PURE__ */ React16.createElement("div", { className: "space-y-4 p-3 rounded-xl bg-white/5 border border-white/5 animate-in fade-in slide-in-from-top-1" }, /* @__PURE__ */ React16.createElement("div", { className: "grid grid-cols-2 gap-3" }, /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Tipo"), /* @__PURE__ */ React16.createElement(
|
|
9312
|
+
"select",
|
|
9313
|
+
{
|
|
9314
|
+
value: recurrenceConfig.type,
|
|
9315
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, type: e.target.value })),
|
|
9316
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg px-2 py-1.5 text-xs text-slate-200 focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9317
|
+
},
|
|
9318
|
+
/* @__PURE__ */ React16.createElement("option", { value: "daily" }, "Di\xE1ria"),
|
|
9319
|
+
/* @__PURE__ */ React16.createElement("option", { value: "weekly" }, "Semanal"),
|
|
9320
|
+
/* @__PURE__ */ React16.createElement("option", { value: "custom" }, "Data Espec\xEDfica")
|
|
9321
|
+
)), recurrenceConfig.type === "weekly" && /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Dia da Semana"), /* @__PURE__ */ React16.createElement(
|
|
9322
|
+
"select",
|
|
9323
|
+
{
|
|
9324
|
+
value: recurrenceConfig.day_of_week,
|
|
9325
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, day_of_week: parseInt(e.target.value, 10) })),
|
|
9326
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg px-2 py-1.5 text-xs text-slate-200 focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9327
|
+
},
|
|
9328
|
+
/* @__PURE__ */ React16.createElement("option", { value: 1 }, "Segunda-feira"),
|
|
9329
|
+
/* @__PURE__ */ React16.createElement("option", { value: 2 }, "Ter\xE7a-feira"),
|
|
9330
|
+
/* @__PURE__ */ React16.createElement("option", { value: 3 }, "Quarta-feira"),
|
|
9331
|
+
/* @__PURE__ */ React16.createElement("option", { value: 4 }, "Quinta-feira"),
|
|
9332
|
+
/* @__PURE__ */ React16.createElement("option", { value: 5 }, "Sexta-feira"),
|
|
9333
|
+
/* @__PURE__ */ React16.createElement("option", { value: 6 }, "S\xE1bado"),
|
|
9334
|
+
/* @__PURE__ */ React16.createElement("option", { value: 0 }, "Domingo")
|
|
9335
|
+
)), recurrenceConfig.type === "custom" && /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Pr\xF3xima Data"), /* @__PURE__ */ React16.createElement(
|
|
9336
|
+
"input",
|
|
9337
|
+
{
|
|
9338
|
+
type: "text",
|
|
9339
|
+
placeholder: "DD/MM/AAAA",
|
|
9340
|
+
value: recurrenceConfig.custom_date,
|
|
9341
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, custom_date: e.target.value })),
|
|
9342
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg px-2 py-1.5 text-xs text-slate-200 focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9343
|
+
}
|
|
9344
|
+
))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-[10px] text-slate-500 uppercase font-bold tracking-tight" }, "Pr\xF3ximo Respons\xE1vel"), /* @__PURE__ */ React16.createElement("div", { className: "relative" }, /* @__PURE__ */ React16.createElement(
|
|
9345
|
+
"select",
|
|
9346
|
+
{
|
|
9347
|
+
value: recurrenceConfig.next_assignee_id,
|
|
9348
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, next_assignee_id: e.target.value })),
|
|
9349
|
+
className: "w-full bg-slate-900/50 border border-white/10 rounded-lg pl-8 pr-2 py-1.5 text-xs text-slate-200 appearance-none focus:outline-none focus:ring-1 focus:ring-indigo-500/50"
|
|
9350
|
+
},
|
|
9351
|
+
/* @__PURE__ */ React16.createElement("option", { value: "" }, "Sem respons\xE1vel"),
|
|
9352
|
+
viewMembers.map((member) => /* @__PURE__ */ React16.createElement("option", { key: member.id, value: member.id }, member.name || member.email))
|
|
9353
|
+
), /* @__PURE__ */ React16.createElement(FiUser2, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-slate-500" }), /* @__PURE__ */ React16.createElement(FiChevronDown6, { className: "absolute right-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-slate-500 pointer-events-none" }))))), /* @__PURE__ */ React16.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React16.createElement(
|
|
9125
9354
|
QuestReviewStackEditor,
|
|
9126
9355
|
{
|
|
9127
9356
|
reviewStack,
|
|
@@ -9776,7 +10005,7 @@ function NodeDetailsPanel({
|
|
|
9776
10005
|
|
|
9777
10006
|
// src/components/QuestDetailsPanel.jsx
|
|
9778
10007
|
import React19, { useState as useState19, useEffect as useEffect16, useRef as useRef14 } from "react";
|
|
9779
|
-
import { FiPlus as FiPlus8, FiX as FiX7, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink7, FiTarget as FiTarget3, FiChevronDown as FiChevronDown7, FiUser as FiUser3, FiSearch as FiSearch7 } from "react-icons/fi";
|
|
10008
|
+
import { FiPlus as FiPlus8, FiX as FiX7, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink7, FiTarget as FiTarget3, FiChevronDown as FiChevronDown7, FiUser as FiUser3, FiSearch as FiSearch7, FiRepeat as FiRepeat2 } from "react-icons/fi";
|
|
9780
10009
|
|
|
9781
10010
|
// src/components/QuestTimeline.jsx
|
|
9782
10011
|
import React18 from "react";
|
|
@@ -9918,12 +10147,20 @@ function QuestDetailsPanel({
|
|
|
9918
10147
|
const [isSaving, setIsSaving] = useState19(false);
|
|
9919
10148
|
const [isLinkCopied, setIsLinkCopied] = useState19(false);
|
|
9920
10149
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState19(false);
|
|
10150
|
+
const [questDate, setQuestDate] = useState19((node == null ? void 0 : node.Date) || null);
|
|
9921
10151
|
const [noteText, setNoteText] = useState19("");
|
|
9922
10152
|
const [noteLinks, setNoteLinks] = useState19([]);
|
|
9923
10153
|
const [noteImages, setNoteImages] = useState19([]);
|
|
9924
10154
|
const [isNoteFormOpen, setIsNoteFormOpen] = useState19(false);
|
|
9925
10155
|
const [editingEntryId, setEditingEntryId] = useState19(null);
|
|
9926
10156
|
const [editingEntryLabel, setEditingEntryLabel] = useState19("");
|
|
10157
|
+
const [recurrenceConfig, setRecurrenceConfig] = useState19((node == null ? void 0 : node.recurrence_config) || {
|
|
10158
|
+
enabled: false,
|
|
10159
|
+
type: "daily",
|
|
10160
|
+
day_of_week: 1,
|
|
10161
|
+
custom_date: "",
|
|
10162
|
+
next_assignee_id: ""
|
|
10163
|
+
});
|
|
9927
10164
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9928
10165
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
9929
10166
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -9959,6 +10196,14 @@ function QuestDetailsPanel({
|
|
|
9959
10196
|
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
9960
10197
|
setReviewStack((node == null ? void 0 : node.reviewStack) || []);
|
|
9961
10198
|
setTimeline((node == null ? void 0 : node.timeline) || []);
|
|
10199
|
+
setQuestDate((node == null ? void 0 : node.Date) || null);
|
|
10200
|
+
setRecurrenceConfig((node == null ? void 0 : node.recurrence_config) || {
|
|
10201
|
+
enabled: false,
|
|
10202
|
+
type: "daily",
|
|
10203
|
+
day_of_week: 1,
|
|
10204
|
+
custom_date: "",
|
|
10205
|
+
next_assignee_id: ""
|
|
10206
|
+
});
|
|
9962
10207
|
setHasUnsavedChanges(false);
|
|
9963
10208
|
}
|
|
9964
10209
|
}, [node]);
|
|
@@ -10054,6 +10299,7 @@ function QuestDetailsPanel({
|
|
|
10054
10299
|
setIsSaving(false);
|
|
10055
10300
|
}
|
|
10056
10301
|
};
|
|
10302
|
+
const filteredCustomProps = customProps.filter((p) => p.key !== "Date" && p.key !== "Data");
|
|
10057
10303
|
const handleAddTimelineNote = async () => {
|
|
10058
10304
|
if (!noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving) return;
|
|
10059
10305
|
setIsSaving(true);
|
|
@@ -10210,6 +10456,7 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10210
10456
|
const currentTimeline = overrides.timeline !== void 0 ? overrides.timeline : timeline;
|
|
10211
10457
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
10212
10458
|
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
10459
|
+
const currentRecurrenceConfig = overrides.recurrenceConfig !== void 0 ? overrides.recurrenceConfig : recurrenceConfig;
|
|
10213
10460
|
if (!keepOpen && !hasUnsavedChanges) {
|
|
10214
10461
|
onClose();
|
|
10215
10462
|
return;
|
|
@@ -10233,11 +10480,13 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10233
10480
|
status: currentStatus,
|
|
10234
10481
|
assignee_id: currentAssigneeId || null,
|
|
10235
10482
|
size,
|
|
10236
|
-
description: currentDescription,
|
|
10483
|
+
description: currentDescription.trim(),
|
|
10237
10484
|
description_sections: processedSections,
|
|
10485
|
+
intensity,
|
|
10486
|
+
recurrence_config: currentRecurrenceConfig,
|
|
10487
|
+
Date: questDate,
|
|
10238
10488
|
useImageAsTexture: false,
|
|
10239
10489
|
textureImageUrl: null,
|
|
10240
|
-
intensity,
|
|
10241
10490
|
is_quest: true,
|
|
10242
10491
|
reviewStack: currentReviewStack,
|
|
10243
10492
|
timeline: currentTimeline,
|
|
@@ -12612,7 +12861,7 @@ function XViewScene({
|
|
|
12612
12861
|
}
|
|
12613
12862
|
}
|
|
12614
12863
|
Object.values(nodeObjects).forEach((mesh) => {
|
|
12615
|
-
const oldLabel = mesh.getObjectByName("timelineLabel");
|
|
12864
|
+
const oldLabel = mesh.getObjectByName("timelineLabel") || mesh.getObjectByName("questDateLabel");
|
|
12616
12865
|
if (oldLabel) {
|
|
12617
12866
|
mesh.remove(oldLabel);
|
|
12618
12867
|
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
@@ -13045,8 +13294,16 @@ function XViewScene({
|
|
|
13045
13294
|
);
|
|
13046
13295
|
const handleActivateQuestLens = useCallback4(({ assigneeId, status: status2 }) => {
|
|
13047
13296
|
var _a2;
|
|
13048
|
-
const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
|
|
13297
|
+
const { nodeObjects, tweenGroup, graphGroup, timelineIntervalsGroup } = stateRef.current;
|
|
13049
13298
|
if (!nodeObjects || !tweenGroup || !graphGroup) return;
|
|
13299
|
+
Object.values(nodeObjects).forEach((mesh) => {
|
|
13300
|
+
const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
|
|
13301
|
+
if (oldLabel) {
|
|
13302
|
+
mesh.remove(oldLabel);
|
|
13303
|
+
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
13304
|
+
oldLabel.material.dispose();
|
|
13305
|
+
}
|
|
13306
|
+
});
|
|
13050
13307
|
const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
|
|
13051
13308
|
const filteredQuests = allQuests.filter((q) => {
|
|
13052
13309
|
const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
|
|
@@ -13068,6 +13325,60 @@ function XViewScene({
|
|
|
13068
13325
|
questsByStatus[q.status].push(q);
|
|
13069
13326
|
}
|
|
13070
13327
|
});
|
|
13328
|
+
const parseDate = (str) => {
|
|
13329
|
+
if (!str) return null;
|
|
13330
|
+
const parts = str.split("/");
|
|
13331
|
+
if (parts.length === 3) {
|
|
13332
|
+
const day = parseInt(parts[0], 10);
|
|
13333
|
+
const month = parseInt(parts[1], 10) - 1;
|
|
13334
|
+
const year = parseInt(parts[2], 10);
|
|
13335
|
+
if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
|
|
13336
|
+
return new Date(year, month, day);
|
|
13337
|
+
}
|
|
13338
|
+
}
|
|
13339
|
+
return null;
|
|
13340
|
+
};
|
|
13341
|
+
const timePoints = /* @__PURE__ */ new Set();
|
|
13342
|
+
const questTimeInfos = /* @__PURE__ */ new Map();
|
|
13343
|
+
filteredQuests.forEach((q) => {
|
|
13344
|
+
const dateProp = q.Date;
|
|
13345
|
+
let info = { isUndated: true, label: "" };
|
|
13346
|
+
if (dateProp) {
|
|
13347
|
+
if (dateProp.date) {
|
|
13348
|
+
const d = parseDate(dateProp.date);
|
|
13349
|
+
if (d) {
|
|
13350
|
+
info = { startDate: d, endDate: d, label: dateProp.date, isUndated: false };
|
|
13351
|
+
timePoints.add(d.getTime());
|
|
13352
|
+
}
|
|
13353
|
+
} else if (dateProp.year) {
|
|
13354
|
+
const y = parseInt(dateProp.year, 10);
|
|
13355
|
+
if (!isNaN(y)) {
|
|
13356
|
+
const d = new Date(y, 0, 1);
|
|
13357
|
+
info = { startDate: d, endDate: d, label: String(y), isUndated: false };
|
|
13358
|
+
timePoints.add(d.getTime());
|
|
13359
|
+
}
|
|
13360
|
+
} else if (dateProp.date_interval && dateProp.date_interval.start) {
|
|
13361
|
+
const sY = parseInt(dateProp.date_interval.start, 10);
|
|
13362
|
+
const eY = parseInt(dateProp.date_interval.end, 10) || sY;
|
|
13363
|
+
if (!isNaN(sY)) {
|
|
13364
|
+
const sd = new Date(sY, 0, 1);
|
|
13365
|
+
const ed = new Date(eY, 11, 31);
|
|
13366
|
+
info = { startDate: sd, endDate: ed, label: `${sY}-${eY}`, isUndated: false };
|
|
13367
|
+
timePoints.add(sd.getTime());
|
|
13368
|
+
timePoints.add(ed.getTime());
|
|
13369
|
+
}
|
|
13370
|
+
}
|
|
13371
|
+
}
|
|
13372
|
+
questTimeInfos.set(String(q.id), info);
|
|
13373
|
+
});
|
|
13374
|
+
const sortedTimePoints = Array.from(timePoints).sort((a, b) => a - b);
|
|
13375
|
+
const timeToYMap = /* @__PURE__ */ new Map();
|
|
13376
|
+
if (sortedTimePoints.length > 0) {
|
|
13377
|
+
const maxIdx = sortedTimePoints.length - 1;
|
|
13378
|
+
sortedTimePoints.forEach((t, i) => {
|
|
13379
|
+
timeToYMap.set(t, (i - maxIdx) * (QUEST_LENS_ROW_SPACING || 30));
|
|
13380
|
+
});
|
|
13381
|
+
}
|
|
13071
13382
|
const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
|
|
13072
13383
|
Object.keys(nodeObjects).forEach((id) => {
|
|
13073
13384
|
const mesh = nodeObjects[id];
|
|
@@ -13104,10 +13415,23 @@ function XViewScene({
|
|
|
13104
13415
|
if (!mesh) {
|
|
13105
13416
|
mesh = addOrUpdateNodeMesh(q, new THREE3.Vector3(colX, 150, 0), true);
|
|
13106
13417
|
}
|
|
13107
|
-
const
|
|
13418
|
+
const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
|
|
13419
|
+
let targetY;
|
|
13420
|
+
if (!timeInfo.isUndated) {
|
|
13421
|
+
targetY = timeToYMap.get(timeInfo.startDate.getTime());
|
|
13422
|
+
} else {
|
|
13423
|
+
const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
|
|
13424
|
+
targetY = -80 - rowIndex * (QUEST_LENS_ROW_SPACING || 30) - undatedOffset;
|
|
13425
|
+
}
|
|
13108
13426
|
const lensTween = new Tween2(mesh.position).to({ x: colX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
|
|
13109
13427
|
tweenGroup.add(lensTween);
|
|
13110
13428
|
lensTween.start();
|
|
13429
|
+
if (!timeInfo.isUndated && timeInfo.label) {
|
|
13430
|
+
const dateSprite = createTextSprite(timeInfo.label, 36);
|
|
13431
|
+
dateSprite.name = "questDateLabel";
|
|
13432
|
+
dateSprite.position.set(0, 3.5, 0);
|
|
13433
|
+
mesh.add(dateSprite);
|
|
13434
|
+
}
|
|
13111
13435
|
if (mesh.userData.labelObject) {
|
|
13112
13436
|
const labelTargetPos = new THREE3.Vector3(colX, targetY, 0).add(
|
|
13113
13437
|
mesh.userData.labelOffset || new THREE3.Vector3(0, -2.5, 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lv-x-software-house/x_view",
|
|
3
|
-
"version": "1.2.5-dev.
|
|
3
|
+
"version": "1.2.5-dev.38",
|
|
4
4
|
"description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
|
|
5
5
|
"author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
|
|
6
6
|
"license": "UNLICENSED",
|