@lv-x-software-house/x_view 1.2.5-dev.37 → 1.2.5-dev.39
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 +338 -13
- package/dist/index.mjs +342 -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,67 @@ 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
|
+
reviewStack: (nodeToSave.reviewStack || []).map((r) => ({ ...r, status: "pending" })),
|
|
2924
|
+
recurrence_config: nextRecurrenceConfig
|
|
2925
|
+
};
|
|
2926
|
+
specificParentData.nodes.push(nextQuestNode);
|
|
2927
|
+
if (stateRef.current.nodeObjects[String(nodeToSave.id)]) {
|
|
2928
|
+
const pos = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
|
|
2929
|
+
pos.x += 12;
|
|
2930
|
+
addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2882
2934
|
try {
|
|
2883
|
-
const isView = ((
|
|
2935
|
+
const isView = ((_c = context.viewType) == null ? void 0 : _c.toLowerCase()) === "view";
|
|
2884
2936
|
if (isView && parentFileId === context.sceneConfigId) {
|
|
2885
2937
|
const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2886
2938
|
if (visualNodeIndex > -1) {
|
|
@@ -3274,6 +3326,8 @@ var IGNORED_KEYS = [
|
|
|
3274
3326
|
"is_quest",
|
|
3275
3327
|
"raw_title",
|
|
3276
3328
|
"assignee_id",
|
|
3329
|
+
"Date",
|
|
3330
|
+
"recurrence_config",
|
|
3277
3331
|
"reviewStack",
|
|
3278
3332
|
"timeline"
|
|
3279
3333
|
];
|
|
@@ -3736,10 +3790,44 @@ function createTimelineEntry(actorId, description, type = "comment", extras = {}
|
|
|
3736
3790
|
id: img.id || v4_default(),
|
|
3737
3791
|
name: img.name || "",
|
|
3738
3792
|
value: img.value || ""
|
|
3739
|
-
}))
|
|
3740
|
-
metadata
|
|
3793
|
+
}))
|
|
3741
3794
|
};
|
|
3742
3795
|
}
|
|
3796
|
+
function calculateNextRecurrenceDate(config) {
|
|
3797
|
+
if (!config || !config.enabled) return null;
|
|
3798
|
+
const now = /* @__PURE__ */ new Date();
|
|
3799
|
+
let nextDate = new Date(now);
|
|
3800
|
+
switch (config.type) {
|
|
3801
|
+
case "daily":
|
|
3802
|
+
nextDate.setDate(now.getDate() + 1);
|
|
3803
|
+
break;
|
|
3804
|
+
case "weekly":
|
|
3805
|
+
const targetDay = parseInt(config.day_of_week, 10);
|
|
3806
|
+
const currentDay = now.getDay();
|
|
3807
|
+
let daysUntilNext = targetDay - currentDay;
|
|
3808
|
+
if (daysUntilNext <= 0) daysUntilNext += 7;
|
|
3809
|
+
nextDate.setDate(now.getDate() + daysUntilNext);
|
|
3810
|
+
break;
|
|
3811
|
+
case "custom":
|
|
3812
|
+
if (config.custom_date) {
|
|
3813
|
+
const parts = config.custom_date.split("/");
|
|
3814
|
+
if (parts.length === 3) {
|
|
3815
|
+
nextDate = new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0], 10));
|
|
3816
|
+
} else {
|
|
3817
|
+
return null;
|
|
3818
|
+
}
|
|
3819
|
+
} else {
|
|
3820
|
+
return null;
|
|
3821
|
+
}
|
|
3822
|
+
break;
|
|
3823
|
+
default:
|
|
3824
|
+
return null;
|
|
3825
|
+
}
|
|
3826
|
+
const d = String(nextDate.getDate()).padStart(2, "0");
|
|
3827
|
+
const m = String(nextDate.getMonth() + 1).padStart(2, "0");
|
|
3828
|
+
const y = nextDate.getFullYear();
|
|
3829
|
+
return { date: `${d}/${m}/${y}` };
|
|
3830
|
+
}
|
|
3743
3831
|
|
|
3744
3832
|
// src/components/CustomPropertyDisplay.jsx
|
|
3745
3833
|
var import_react4 = __toESM(require("react"));
|
|
@@ -8866,7 +8954,15 @@ function InSceneQuestForm({
|
|
|
8866
8954
|
const [size, setSize] = (0, import_react17.useState)("medium");
|
|
8867
8955
|
const [intensity, setIntensity] = (0, import_react17.useState)(0);
|
|
8868
8956
|
const [description, setDescription] = (0, import_react17.useState)("");
|
|
8957
|
+
const [recurrenceConfig, setRecurrenceConfig] = (0, import_react17.useState)({
|
|
8958
|
+
enabled: false,
|
|
8959
|
+
type: "daily",
|
|
8960
|
+
day_of_week: 1,
|
|
8961
|
+
custom_date: "",
|
|
8962
|
+
next_assignee_id: ""
|
|
8963
|
+
});
|
|
8869
8964
|
const [reviewStack, setReviewStack] = (0, import_react17.useState)([]);
|
|
8965
|
+
const [questDate, setQuestDate] = (0, import_react17.useState)(null);
|
|
8870
8966
|
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react17.useState)(false);
|
|
8871
8967
|
const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react17.useState)(false);
|
|
8872
8968
|
const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react17.useState)("");
|
|
@@ -8938,6 +9034,8 @@ function InSceneQuestForm({
|
|
|
8938
9034
|
textureImageUrl: null,
|
|
8939
9035
|
reviewStack,
|
|
8940
9036
|
timeline: initialTimeline,
|
|
9037
|
+
Date: questDate,
|
|
9038
|
+
recurrence_config: recurrenceConfig,
|
|
8941
9039
|
...additionalData
|
|
8942
9040
|
});
|
|
8943
9041
|
};
|
|
@@ -9104,7 +9202,139 @@ function InSceneQuestForm({
|
|
|
9104
9202
|
)), viewMembers.filter((member) => {
|
|
9105
9203
|
const search = assigneeSearchQuery.toLowerCase();
|
|
9106
9204
|
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: "
|
|
9205
|
+
}).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(
|
|
9206
|
+
"button",
|
|
9207
|
+
{
|
|
9208
|
+
type: "button",
|
|
9209
|
+
onClick: () => setQuestDate({ type: "Data", value: "" }),
|
|
9210
|
+
className: "text-[10px] text-indigo-400 hover:text-indigo-300 font-bold uppercase transition-colors"
|
|
9211
|
+
},
|
|
9212
|
+
"+ Adicionar"
|
|
9213
|
+
)), 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(
|
|
9214
|
+
"button",
|
|
9215
|
+
{
|
|
9216
|
+
type: "button",
|
|
9217
|
+
onClick: () => setQuestDate(null),
|
|
9218
|
+
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",
|
|
9219
|
+
title: "Remover data"
|
|
9220
|
+
},
|
|
9221
|
+
/* @__PURE__ */ import_react17.default.createElement(import_fi15.FiX, { size: 12 })
|
|
9222
|
+
), /* @__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(
|
|
9223
|
+
"button",
|
|
9224
|
+
{
|
|
9225
|
+
key: t,
|
|
9226
|
+
type: "button",
|
|
9227
|
+
onClick: () => {
|
|
9228
|
+
const newDate = { type: t };
|
|
9229
|
+
if (t === "Date Interval") {
|
|
9230
|
+
newDate.start = "";
|
|
9231
|
+
newDate.end = "";
|
|
9232
|
+
} else {
|
|
9233
|
+
newDate.value = "";
|
|
9234
|
+
}
|
|
9235
|
+
setQuestDate(newDate);
|
|
9236
|
+
},
|
|
9237
|
+
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"}`
|
|
9238
|
+
},
|
|
9239
|
+
t === "Date Interval" ? "Intervalo" : t
|
|
9240
|
+
))), questDate.type === "Data" && /* @__PURE__ */ import_react17.default.createElement(
|
|
9241
|
+
"input",
|
|
9242
|
+
{
|
|
9243
|
+
type: "text",
|
|
9244
|
+
placeholder: "DD/MM/AAAA",
|
|
9245
|
+
value: questDate.value || "",
|
|
9246
|
+
onChange: (e) => {
|
|
9247
|
+
const rawValue = e.target.value;
|
|
9248
|
+
const digits = rawValue.replace(/\D/g, "");
|
|
9249
|
+
const len = digits.length;
|
|
9250
|
+
let formattedValue = digits;
|
|
9251
|
+
if (len > 2 && len <= 4)
|
|
9252
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2)}`;
|
|
9253
|
+
else if (len > 4)
|
|
9254
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4, 8)}`;
|
|
9255
|
+
setQuestDate({ ...questDate, value: formattedValue });
|
|
9256
|
+
},
|
|
9257
|
+
maxLength: "10",
|
|
9258
|
+
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"
|
|
9259
|
+
}
|
|
9260
|
+
), questDate.type === "Ano" && /* @__PURE__ */ import_react17.default.createElement(
|
|
9261
|
+
"input",
|
|
9262
|
+
{
|
|
9263
|
+
type: "number",
|
|
9264
|
+
placeholder: "AAAA",
|
|
9265
|
+
value: questDate.value || "",
|
|
9266
|
+
onChange: (e) => setQuestDate({ ...questDate, value: e.target.value }),
|
|
9267
|
+
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"
|
|
9268
|
+
}
|
|
9269
|
+
), questDate.type === "Date Interval" && /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
9270
|
+
"input",
|
|
9271
|
+
{
|
|
9272
|
+
type: "number",
|
|
9273
|
+
placeholder: "In\xEDcio (Ano)",
|
|
9274
|
+
value: questDate.start || "",
|
|
9275
|
+
onChange: (e) => setQuestDate({ ...questDate, start: e.target.value }),
|
|
9276
|
+
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"
|
|
9277
|
+
}
|
|
9278
|
+
), /* @__PURE__ */ import_react17.default.createElement("span", { className: "text-slate-500" }, "-"), /* @__PURE__ */ import_react17.default.createElement(
|
|
9279
|
+
"input",
|
|
9280
|
+
{
|
|
9281
|
+
type: "number",
|
|
9282
|
+
placeholder: "Fim (Ano)",
|
|
9283
|
+
value: questDate.end || "",
|
|
9284
|
+
onChange: (e) => setQuestDate({ ...questDate, end: e.target.value }),
|
|
9285
|
+
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"
|
|
9286
|
+
}
|
|
9287
|
+
)))), /* @__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(
|
|
9288
|
+
"button",
|
|
9289
|
+
{
|
|
9290
|
+
type: "button",
|
|
9291
|
+
onClick: () => setRecurrenceConfig((prev) => ({ ...prev, enabled: !prev.enabled })),
|
|
9292
|
+
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`
|
|
9293
|
+
},
|
|
9294
|
+
/* @__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"}` })
|
|
9295
|
+
)), 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(
|
|
9296
|
+
"select",
|
|
9297
|
+
{
|
|
9298
|
+
value: recurrenceConfig.type,
|
|
9299
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, type: e.target.value })),
|
|
9300
|
+
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"
|
|
9301
|
+
},
|
|
9302
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "daily" }, "Di\xE1ria"),
|
|
9303
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "weekly" }, "Semanal"),
|
|
9304
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "custom" }, "Data Espec\xEDfica")
|
|
9305
|
+
)), 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(
|
|
9306
|
+
"select",
|
|
9307
|
+
{
|
|
9308
|
+
value: recurrenceConfig.day_of_week,
|
|
9309
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, day_of_week: parseInt(e.target.value, 10) })),
|
|
9310
|
+
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"
|
|
9311
|
+
},
|
|
9312
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 1 }, "Segunda-feira"),
|
|
9313
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 2 }, "Ter\xE7a-feira"),
|
|
9314
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 3 }, "Quarta-feira"),
|
|
9315
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 4 }, "Quinta-feira"),
|
|
9316
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 5 }, "Sexta-feira"),
|
|
9317
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 6 }, "S\xE1bado"),
|
|
9318
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: 0 }, "Domingo")
|
|
9319
|
+
)), 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(
|
|
9320
|
+
"input",
|
|
9321
|
+
{
|
|
9322
|
+
type: "text",
|
|
9323
|
+
placeholder: "DD/MM/AAAA",
|
|
9324
|
+
value: recurrenceConfig.custom_date,
|
|
9325
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, custom_date: e.target.value })),
|
|
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__ */ 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(
|
|
9329
|
+
"select",
|
|
9330
|
+
{
|
|
9331
|
+
value: recurrenceConfig.next_assignee_id,
|
|
9332
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, next_assignee_id: e.target.value })),
|
|
9333
|
+
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"
|
|
9334
|
+
},
|
|
9335
|
+
/* @__PURE__ */ import_react17.default.createElement("option", { value: "" }, "Sem respons\xE1vel"),
|
|
9336
|
+
viewMembers.map((member) => /* @__PURE__ */ import_react17.default.createElement("option", { key: member.id, value: member.id }, member.name || member.email))
|
|
9337
|
+
), /* @__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
9338
|
QuestReviewStackEditor,
|
|
9109
9339
|
{
|
|
9110
9340
|
reviewStack,
|
|
@@ -9889,12 +10119,20 @@ function QuestDetailsPanel({
|
|
|
9889
10119
|
const [isSaving, setIsSaving] = (0, import_react20.useState)(false);
|
|
9890
10120
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react20.useState)(false);
|
|
9891
10121
|
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react20.useState)(false);
|
|
10122
|
+
const [questDate, setQuestDate] = (0, import_react20.useState)((node == null ? void 0 : node.Date) || null);
|
|
9892
10123
|
const [noteText, setNoteText] = (0, import_react20.useState)("");
|
|
9893
10124
|
const [noteLinks, setNoteLinks] = (0, import_react20.useState)([]);
|
|
9894
10125
|
const [noteImages, setNoteImages] = (0, import_react20.useState)([]);
|
|
9895
10126
|
const [isNoteFormOpen, setIsNoteFormOpen] = (0, import_react20.useState)(false);
|
|
9896
10127
|
const [editingEntryId, setEditingEntryId] = (0, import_react20.useState)(null);
|
|
9897
10128
|
const [editingEntryLabel, setEditingEntryLabel] = (0, import_react20.useState)("");
|
|
10129
|
+
const [recurrenceConfig, setRecurrenceConfig] = (0, import_react20.useState)((node == null ? void 0 : node.recurrence_config) || {
|
|
10130
|
+
enabled: false,
|
|
10131
|
+
type: "daily",
|
|
10132
|
+
day_of_week: 1,
|
|
10133
|
+
custom_date: "",
|
|
10134
|
+
next_assignee_id: ""
|
|
10135
|
+
});
|
|
9898
10136
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9899
10137
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
9900
10138
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -9930,6 +10168,14 @@ function QuestDetailsPanel({
|
|
|
9930
10168
|
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
9931
10169
|
setReviewStack((node == null ? void 0 : node.reviewStack) || []);
|
|
9932
10170
|
setTimeline((node == null ? void 0 : node.timeline) || []);
|
|
10171
|
+
setQuestDate((node == null ? void 0 : node.Date) || null);
|
|
10172
|
+
setRecurrenceConfig((node == null ? void 0 : node.recurrence_config) || {
|
|
10173
|
+
enabled: false,
|
|
10174
|
+
type: "daily",
|
|
10175
|
+
day_of_week: 1,
|
|
10176
|
+
custom_date: "",
|
|
10177
|
+
next_assignee_id: ""
|
|
10178
|
+
});
|
|
9933
10179
|
setHasUnsavedChanges(false);
|
|
9934
10180
|
}
|
|
9935
10181
|
}, [node]);
|
|
@@ -10025,6 +10271,7 @@ function QuestDetailsPanel({
|
|
|
10025
10271
|
setIsSaving(false);
|
|
10026
10272
|
}
|
|
10027
10273
|
};
|
|
10274
|
+
const filteredCustomProps = customProps.filter((p) => p.key !== "Date" && p.key !== "Data");
|
|
10028
10275
|
const handleAddTimelineNote = async () => {
|
|
10029
10276
|
if (!noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving) return;
|
|
10030
10277
|
setIsSaving(true);
|
|
@@ -10181,6 +10428,7 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10181
10428
|
const currentTimeline = overrides.timeline !== void 0 ? overrides.timeline : timeline;
|
|
10182
10429
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
10183
10430
|
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
10431
|
+
const currentRecurrenceConfig = overrides.recurrenceConfig !== void 0 ? overrides.recurrenceConfig : recurrenceConfig;
|
|
10184
10432
|
if (!keepOpen && !hasUnsavedChanges) {
|
|
10185
10433
|
onClose();
|
|
10186
10434
|
return;
|
|
@@ -10204,11 +10452,13 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10204
10452
|
status: currentStatus,
|
|
10205
10453
|
assignee_id: currentAssigneeId || null,
|
|
10206
10454
|
size,
|
|
10207
|
-
description: currentDescription,
|
|
10455
|
+
description: currentDescription.trim(),
|
|
10208
10456
|
description_sections: processedSections,
|
|
10457
|
+
intensity,
|
|
10458
|
+
recurrence_config: currentRecurrenceConfig,
|
|
10459
|
+
Date: questDate,
|
|
10209
10460
|
useImageAsTexture: false,
|
|
10210
10461
|
textureImageUrl: null,
|
|
10211
|
-
intensity,
|
|
10212
10462
|
is_quest: true,
|
|
10213
10463
|
reviewStack: currentReviewStack,
|
|
10214
10464
|
timeline: currentTimeline,
|
|
@@ -12570,7 +12820,7 @@ function XViewScene({
|
|
|
12570
12820
|
}
|
|
12571
12821
|
}
|
|
12572
12822
|
Object.values(nodeObjects).forEach((mesh) => {
|
|
12573
|
-
const oldLabel = mesh.getObjectByName("timelineLabel");
|
|
12823
|
+
const oldLabel = mesh.getObjectByName("timelineLabel") || mesh.getObjectByName("questDateLabel");
|
|
12574
12824
|
if (oldLabel) {
|
|
12575
12825
|
mesh.remove(oldLabel);
|
|
12576
12826
|
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
@@ -13003,8 +13253,16 @@ function XViewScene({
|
|
|
13003
13253
|
);
|
|
13004
13254
|
const handleActivateQuestLens = (0, import_react28.useCallback)(({ assigneeId, status: status2 }) => {
|
|
13005
13255
|
var _a2;
|
|
13006
|
-
const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
|
|
13256
|
+
const { nodeObjects, tweenGroup, graphGroup, timelineIntervalsGroup } = stateRef.current;
|
|
13007
13257
|
if (!nodeObjects || !tweenGroup || !graphGroup) return;
|
|
13258
|
+
Object.values(nodeObjects).forEach((mesh) => {
|
|
13259
|
+
const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
|
|
13260
|
+
if (oldLabel) {
|
|
13261
|
+
mesh.remove(oldLabel);
|
|
13262
|
+
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
13263
|
+
oldLabel.material.dispose();
|
|
13264
|
+
}
|
|
13265
|
+
});
|
|
13008
13266
|
const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
|
|
13009
13267
|
const filteredQuests = allQuests.filter((q) => {
|
|
13010
13268
|
const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
|
|
@@ -13026,6 +13284,60 @@ function XViewScene({
|
|
|
13026
13284
|
questsByStatus[q.status].push(q);
|
|
13027
13285
|
}
|
|
13028
13286
|
});
|
|
13287
|
+
const parseDate = (str) => {
|
|
13288
|
+
if (!str) return null;
|
|
13289
|
+
const parts = str.split("/");
|
|
13290
|
+
if (parts.length === 3) {
|
|
13291
|
+
const day = parseInt(parts[0], 10);
|
|
13292
|
+
const month = parseInt(parts[1], 10) - 1;
|
|
13293
|
+
const year = parseInt(parts[2], 10);
|
|
13294
|
+
if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
|
|
13295
|
+
return new Date(year, month, day);
|
|
13296
|
+
}
|
|
13297
|
+
}
|
|
13298
|
+
return null;
|
|
13299
|
+
};
|
|
13300
|
+
const timePoints = /* @__PURE__ */ new Set();
|
|
13301
|
+
const questTimeInfos = /* @__PURE__ */ new Map();
|
|
13302
|
+
filteredQuests.forEach((q) => {
|
|
13303
|
+
const dateProp = q.Date;
|
|
13304
|
+
let info = { isUndated: true, label: "" };
|
|
13305
|
+
if (dateProp) {
|
|
13306
|
+
if (dateProp.date) {
|
|
13307
|
+
const d = parseDate(dateProp.date);
|
|
13308
|
+
if (d) {
|
|
13309
|
+
info = { startDate: d, endDate: d, label: dateProp.date, isUndated: false };
|
|
13310
|
+
timePoints.add(d.getTime());
|
|
13311
|
+
}
|
|
13312
|
+
} else if (dateProp.year) {
|
|
13313
|
+
const y = parseInt(dateProp.year, 10);
|
|
13314
|
+
if (!isNaN(y)) {
|
|
13315
|
+
const d = new Date(y, 0, 1);
|
|
13316
|
+
info = { startDate: d, endDate: d, label: String(y), isUndated: false };
|
|
13317
|
+
timePoints.add(d.getTime());
|
|
13318
|
+
}
|
|
13319
|
+
} else if (dateProp.date_interval && dateProp.date_interval.start) {
|
|
13320
|
+
const sY = parseInt(dateProp.date_interval.start, 10);
|
|
13321
|
+
const eY = parseInt(dateProp.date_interval.end, 10) || sY;
|
|
13322
|
+
if (!isNaN(sY)) {
|
|
13323
|
+
const sd = new Date(sY, 0, 1);
|
|
13324
|
+
const ed = new Date(eY, 11, 31);
|
|
13325
|
+
info = { startDate: sd, endDate: ed, label: `${sY}-${eY}`, isUndated: false };
|
|
13326
|
+
timePoints.add(sd.getTime());
|
|
13327
|
+
timePoints.add(ed.getTime());
|
|
13328
|
+
}
|
|
13329
|
+
}
|
|
13330
|
+
}
|
|
13331
|
+
questTimeInfos.set(String(q.id), info);
|
|
13332
|
+
});
|
|
13333
|
+
const sortedTimePoints = Array.from(timePoints).sort((a, b) => a - b);
|
|
13334
|
+
const timeToYMap = /* @__PURE__ */ new Map();
|
|
13335
|
+
if (sortedTimePoints.length > 0) {
|
|
13336
|
+
const maxIdx = sortedTimePoints.length - 1;
|
|
13337
|
+
sortedTimePoints.forEach((t, i) => {
|
|
13338
|
+
timeToYMap.set(t, (i - maxIdx) * (QUEST_LENS_ROW_SPACING || 30));
|
|
13339
|
+
});
|
|
13340
|
+
}
|
|
13029
13341
|
const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
|
|
13030
13342
|
Object.keys(nodeObjects).forEach((id) => {
|
|
13031
13343
|
const mesh = nodeObjects[id];
|
|
@@ -13062,10 +13374,23 @@ function XViewScene({
|
|
|
13062
13374
|
if (!mesh) {
|
|
13063
13375
|
mesh = addOrUpdateNodeMesh(q, new THREE3.Vector3(colX, 150, 0), true);
|
|
13064
13376
|
}
|
|
13065
|
-
const
|
|
13377
|
+
const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
|
|
13378
|
+
let targetY;
|
|
13379
|
+
if (!timeInfo.isUndated) {
|
|
13380
|
+
targetY = timeToYMap.get(timeInfo.startDate.getTime());
|
|
13381
|
+
} else {
|
|
13382
|
+
const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
|
|
13383
|
+
targetY = -80 - rowIndex * (QUEST_LENS_ROW_SPACING || 30) - undatedOffset;
|
|
13384
|
+
}
|
|
13066
13385
|
const lensTween = new import_tween2.Tween(mesh.position).to({ x: colX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
|
|
13067
13386
|
tweenGroup.add(lensTween);
|
|
13068
13387
|
lensTween.start();
|
|
13388
|
+
if (!timeInfo.isUndated && timeInfo.label) {
|
|
13389
|
+
const dateSprite = createTextSprite(timeInfo.label, 36);
|
|
13390
|
+
dateSprite.name = "questDateLabel";
|
|
13391
|
+
dateSprite.position.set(0, 3.5, 0);
|
|
13392
|
+
mesh.add(dateSprite);
|
|
13393
|
+
}
|
|
13069
13394
|
if (mesh.userData.labelObject) {
|
|
13070
13395
|
const labelTargetPos = new THREE3.Vector3(colX, targetY, 0).add(
|
|
13071
13396
|
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,67 @@ 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
|
+
reviewStack: (nodeToSave.reviewStack || []).map((r) => ({ ...r, status: "pending" })),
|
|
2885
|
+
recurrence_config: nextRecurrenceConfig
|
|
2886
|
+
};
|
|
2887
|
+
specificParentData.nodes.push(nextQuestNode);
|
|
2888
|
+
if (stateRef.current.nodeObjects[String(nodeToSave.id)]) {
|
|
2889
|
+
const pos = stateRef.current.nodeObjects[String(nodeToSave.id)].position.clone();
|
|
2890
|
+
pos.x += 12;
|
|
2891
|
+
addStandaloneNodeToScene(stateRef.current, nextQuestNode, pos);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2843
2895
|
try {
|
|
2844
|
-
const isView = ((
|
|
2896
|
+
const isView = ((_c = context.viewType) == null ? void 0 : _c.toLowerCase()) === "view";
|
|
2845
2897
|
if (isView && parentFileId === context.sceneConfigId) {
|
|
2846
2898
|
const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2847
2899
|
if (visualNodeIndex > -1) {
|
|
@@ -3235,6 +3287,8 @@ var IGNORED_KEYS = [
|
|
|
3235
3287
|
"is_quest",
|
|
3236
3288
|
"raw_title",
|
|
3237
3289
|
"assignee_id",
|
|
3290
|
+
"Date",
|
|
3291
|
+
"recurrence_config",
|
|
3238
3292
|
"reviewStack",
|
|
3239
3293
|
"timeline"
|
|
3240
3294
|
];
|
|
@@ -3697,10 +3751,44 @@ function createTimelineEntry(actorId, description, type = "comment", extras = {}
|
|
|
3697
3751
|
id: img.id || v4_default(),
|
|
3698
3752
|
name: img.name || "",
|
|
3699
3753
|
value: img.value || ""
|
|
3700
|
-
}))
|
|
3701
|
-
metadata
|
|
3754
|
+
}))
|
|
3702
3755
|
};
|
|
3703
3756
|
}
|
|
3757
|
+
function calculateNextRecurrenceDate(config) {
|
|
3758
|
+
if (!config || !config.enabled) return null;
|
|
3759
|
+
const now = /* @__PURE__ */ new Date();
|
|
3760
|
+
let nextDate = new Date(now);
|
|
3761
|
+
switch (config.type) {
|
|
3762
|
+
case "daily":
|
|
3763
|
+
nextDate.setDate(now.getDate() + 1);
|
|
3764
|
+
break;
|
|
3765
|
+
case "weekly":
|
|
3766
|
+
const targetDay = parseInt(config.day_of_week, 10);
|
|
3767
|
+
const currentDay = now.getDay();
|
|
3768
|
+
let daysUntilNext = targetDay - currentDay;
|
|
3769
|
+
if (daysUntilNext <= 0) daysUntilNext += 7;
|
|
3770
|
+
nextDate.setDate(now.getDate() + daysUntilNext);
|
|
3771
|
+
break;
|
|
3772
|
+
case "custom":
|
|
3773
|
+
if (config.custom_date) {
|
|
3774
|
+
const parts = config.custom_date.split("/");
|
|
3775
|
+
if (parts.length === 3) {
|
|
3776
|
+
nextDate = new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0], 10));
|
|
3777
|
+
} else {
|
|
3778
|
+
return null;
|
|
3779
|
+
}
|
|
3780
|
+
} else {
|
|
3781
|
+
return null;
|
|
3782
|
+
}
|
|
3783
|
+
break;
|
|
3784
|
+
default:
|
|
3785
|
+
return null;
|
|
3786
|
+
}
|
|
3787
|
+
const d = String(nextDate.getDate()).padStart(2, "0");
|
|
3788
|
+
const m = String(nextDate.getMonth() + 1).padStart(2, "0");
|
|
3789
|
+
const y = nextDate.getFullYear();
|
|
3790
|
+
return { date: `${d}/${m}/${y}` };
|
|
3791
|
+
}
|
|
3704
3792
|
|
|
3705
3793
|
// src/components/CustomPropertyDisplay.jsx
|
|
3706
3794
|
import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
@@ -8684,7 +8772,9 @@ import {
|
|
|
8684
8772
|
FiX as FiX5,
|
|
8685
8773
|
FiChevronDown as FiChevronDown6,
|
|
8686
8774
|
FiUser as FiUser2,
|
|
8687
|
-
FiSearch as FiSearch5
|
|
8775
|
+
FiSearch as FiSearch5,
|
|
8776
|
+
FiCalendar,
|
|
8777
|
+
FiRepeat
|
|
8688
8778
|
} from "react-icons/fi";
|
|
8689
8779
|
|
|
8690
8780
|
// src/components/QuestReviewStackEditor.jsx
|
|
@@ -8883,7 +8973,15 @@ function InSceneQuestForm({
|
|
|
8883
8973
|
const [size, setSize] = useState17("medium");
|
|
8884
8974
|
const [intensity, setIntensity] = useState17(0);
|
|
8885
8975
|
const [description, setDescription] = useState17("");
|
|
8976
|
+
const [recurrenceConfig, setRecurrenceConfig] = useState17({
|
|
8977
|
+
enabled: false,
|
|
8978
|
+
type: "daily",
|
|
8979
|
+
day_of_week: 1,
|
|
8980
|
+
custom_date: "",
|
|
8981
|
+
next_assignee_id: ""
|
|
8982
|
+
});
|
|
8886
8983
|
const [reviewStack, setReviewStack] = useState17([]);
|
|
8984
|
+
const [questDate, setQuestDate] = useState17(null);
|
|
8887
8985
|
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState17(false);
|
|
8888
8986
|
const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = useState17(false);
|
|
8889
8987
|
const [assigneeSearchQuery, setAssigneeSearchQuery] = useState17("");
|
|
@@ -8955,6 +9053,8 @@ function InSceneQuestForm({
|
|
|
8955
9053
|
textureImageUrl: null,
|
|
8956
9054
|
reviewStack,
|
|
8957
9055
|
timeline: initialTimeline,
|
|
9056
|
+
Date: questDate,
|
|
9057
|
+
recurrence_config: recurrenceConfig,
|
|
8958
9058
|
...additionalData
|
|
8959
9059
|
});
|
|
8960
9060
|
};
|
|
@@ -9121,7 +9221,139 @@ function InSceneQuestForm({
|
|
|
9121
9221
|
)), viewMembers.filter((member) => {
|
|
9122
9222
|
const search = assigneeSearchQuery.toLowerCase();
|
|
9123
9223
|
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: "
|
|
9224
|
+
}).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(
|
|
9225
|
+
"button",
|
|
9226
|
+
{
|
|
9227
|
+
type: "button",
|
|
9228
|
+
onClick: () => setQuestDate({ type: "Data", value: "" }),
|
|
9229
|
+
className: "text-[10px] text-indigo-400 hover:text-indigo-300 font-bold uppercase transition-colors"
|
|
9230
|
+
},
|
|
9231
|
+
"+ Adicionar"
|
|
9232
|
+
)), 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(
|
|
9233
|
+
"button",
|
|
9234
|
+
{
|
|
9235
|
+
type: "button",
|
|
9236
|
+
onClick: () => setQuestDate(null),
|
|
9237
|
+
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",
|
|
9238
|
+
title: "Remover data"
|
|
9239
|
+
},
|
|
9240
|
+
/* @__PURE__ */ React16.createElement(FiX5, { size: 12 })
|
|
9241
|
+
), /* @__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(
|
|
9242
|
+
"button",
|
|
9243
|
+
{
|
|
9244
|
+
key: t,
|
|
9245
|
+
type: "button",
|
|
9246
|
+
onClick: () => {
|
|
9247
|
+
const newDate = { type: t };
|
|
9248
|
+
if (t === "Date Interval") {
|
|
9249
|
+
newDate.start = "";
|
|
9250
|
+
newDate.end = "";
|
|
9251
|
+
} else {
|
|
9252
|
+
newDate.value = "";
|
|
9253
|
+
}
|
|
9254
|
+
setQuestDate(newDate);
|
|
9255
|
+
},
|
|
9256
|
+
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"}`
|
|
9257
|
+
},
|
|
9258
|
+
t === "Date Interval" ? "Intervalo" : t
|
|
9259
|
+
))), questDate.type === "Data" && /* @__PURE__ */ React16.createElement(
|
|
9260
|
+
"input",
|
|
9261
|
+
{
|
|
9262
|
+
type: "text",
|
|
9263
|
+
placeholder: "DD/MM/AAAA",
|
|
9264
|
+
value: questDate.value || "",
|
|
9265
|
+
onChange: (e) => {
|
|
9266
|
+
const rawValue = e.target.value;
|
|
9267
|
+
const digits = rawValue.replace(/\D/g, "");
|
|
9268
|
+
const len = digits.length;
|
|
9269
|
+
let formattedValue = digits;
|
|
9270
|
+
if (len > 2 && len <= 4)
|
|
9271
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2)}`;
|
|
9272
|
+
else if (len > 4)
|
|
9273
|
+
formattedValue = `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4, 8)}`;
|
|
9274
|
+
setQuestDate({ ...questDate, value: formattedValue });
|
|
9275
|
+
},
|
|
9276
|
+
maxLength: "10",
|
|
9277
|
+
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"
|
|
9278
|
+
}
|
|
9279
|
+
), questDate.type === "Ano" && /* @__PURE__ */ React16.createElement(
|
|
9280
|
+
"input",
|
|
9281
|
+
{
|
|
9282
|
+
type: "number",
|
|
9283
|
+
placeholder: "AAAA",
|
|
9284
|
+
value: questDate.value || "",
|
|
9285
|
+
onChange: (e) => setQuestDate({ ...questDate, value: e.target.value }),
|
|
9286
|
+
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"
|
|
9287
|
+
}
|
|
9288
|
+
), questDate.type === "Date Interval" && /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(
|
|
9289
|
+
"input",
|
|
9290
|
+
{
|
|
9291
|
+
type: "number",
|
|
9292
|
+
placeholder: "In\xEDcio (Ano)",
|
|
9293
|
+
value: questDate.start || "",
|
|
9294
|
+
onChange: (e) => setQuestDate({ ...questDate, start: e.target.value }),
|
|
9295
|
+
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"
|
|
9296
|
+
}
|
|
9297
|
+
), /* @__PURE__ */ React16.createElement("span", { className: "text-slate-500" }, "-"), /* @__PURE__ */ React16.createElement(
|
|
9298
|
+
"input",
|
|
9299
|
+
{
|
|
9300
|
+
type: "number",
|
|
9301
|
+
placeholder: "Fim (Ano)",
|
|
9302
|
+
value: questDate.end || "",
|
|
9303
|
+
onChange: (e) => setQuestDate({ ...questDate, end: e.target.value }),
|
|
9304
|
+
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"
|
|
9305
|
+
}
|
|
9306
|
+
)))), /* @__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(
|
|
9307
|
+
"button",
|
|
9308
|
+
{
|
|
9309
|
+
type: "button",
|
|
9310
|
+
onClick: () => setRecurrenceConfig((prev) => ({ ...prev, enabled: !prev.enabled })),
|
|
9311
|
+
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`
|
|
9312
|
+
},
|
|
9313
|
+
/* @__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"}` })
|
|
9314
|
+
)), 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(
|
|
9315
|
+
"select",
|
|
9316
|
+
{
|
|
9317
|
+
value: recurrenceConfig.type,
|
|
9318
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, type: e.target.value })),
|
|
9319
|
+
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"
|
|
9320
|
+
},
|
|
9321
|
+
/* @__PURE__ */ React16.createElement("option", { value: "daily" }, "Di\xE1ria"),
|
|
9322
|
+
/* @__PURE__ */ React16.createElement("option", { value: "weekly" }, "Semanal"),
|
|
9323
|
+
/* @__PURE__ */ React16.createElement("option", { value: "custom" }, "Data Espec\xEDfica")
|
|
9324
|
+
)), 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(
|
|
9325
|
+
"select",
|
|
9326
|
+
{
|
|
9327
|
+
value: recurrenceConfig.day_of_week,
|
|
9328
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, day_of_week: parseInt(e.target.value, 10) })),
|
|
9329
|
+
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"
|
|
9330
|
+
},
|
|
9331
|
+
/* @__PURE__ */ React16.createElement("option", { value: 1 }, "Segunda-feira"),
|
|
9332
|
+
/* @__PURE__ */ React16.createElement("option", { value: 2 }, "Ter\xE7a-feira"),
|
|
9333
|
+
/* @__PURE__ */ React16.createElement("option", { value: 3 }, "Quarta-feira"),
|
|
9334
|
+
/* @__PURE__ */ React16.createElement("option", { value: 4 }, "Quinta-feira"),
|
|
9335
|
+
/* @__PURE__ */ React16.createElement("option", { value: 5 }, "Sexta-feira"),
|
|
9336
|
+
/* @__PURE__ */ React16.createElement("option", { value: 6 }, "S\xE1bado"),
|
|
9337
|
+
/* @__PURE__ */ React16.createElement("option", { value: 0 }, "Domingo")
|
|
9338
|
+
)), 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(
|
|
9339
|
+
"input",
|
|
9340
|
+
{
|
|
9341
|
+
type: "text",
|
|
9342
|
+
placeholder: "DD/MM/AAAA",
|
|
9343
|
+
value: recurrenceConfig.custom_date,
|
|
9344
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, custom_date: e.target.value })),
|
|
9345
|
+
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"
|
|
9346
|
+
}
|
|
9347
|
+
))), /* @__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(
|
|
9348
|
+
"select",
|
|
9349
|
+
{
|
|
9350
|
+
value: recurrenceConfig.next_assignee_id,
|
|
9351
|
+
onChange: (e) => setRecurrenceConfig((prev) => ({ ...prev, next_assignee_id: e.target.value })),
|
|
9352
|
+
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"
|
|
9353
|
+
},
|
|
9354
|
+
/* @__PURE__ */ React16.createElement("option", { value: "" }, "Sem respons\xE1vel"),
|
|
9355
|
+
viewMembers.map((member) => /* @__PURE__ */ React16.createElement("option", { key: member.id, value: member.id }, member.name || member.email))
|
|
9356
|
+
), /* @__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
9357
|
QuestReviewStackEditor,
|
|
9126
9358
|
{
|
|
9127
9359
|
reviewStack,
|
|
@@ -9776,7 +10008,7 @@ function NodeDetailsPanel({
|
|
|
9776
10008
|
|
|
9777
10009
|
// src/components/QuestDetailsPanel.jsx
|
|
9778
10010
|
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";
|
|
10011
|
+
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
10012
|
|
|
9781
10013
|
// src/components/QuestTimeline.jsx
|
|
9782
10014
|
import React18 from "react";
|
|
@@ -9918,12 +10150,20 @@ function QuestDetailsPanel({
|
|
|
9918
10150
|
const [isSaving, setIsSaving] = useState19(false);
|
|
9919
10151
|
const [isLinkCopied, setIsLinkCopied] = useState19(false);
|
|
9920
10152
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState19(false);
|
|
10153
|
+
const [questDate, setQuestDate] = useState19((node == null ? void 0 : node.Date) || null);
|
|
9921
10154
|
const [noteText, setNoteText] = useState19("");
|
|
9922
10155
|
const [noteLinks, setNoteLinks] = useState19([]);
|
|
9923
10156
|
const [noteImages, setNoteImages] = useState19([]);
|
|
9924
10157
|
const [isNoteFormOpen, setIsNoteFormOpen] = useState19(false);
|
|
9925
10158
|
const [editingEntryId, setEditingEntryId] = useState19(null);
|
|
9926
10159
|
const [editingEntryLabel, setEditingEntryLabel] = useState19("");
|
|
10160
|
+
const [recurrenceConfig, setRecurrenceConfig] = useState19((node == null ? void 0 : node.recurrence_config) || {
|
|
10161
|
+
enabled: false,
|
|
10162
|
+
type: "daily",
|
|
10163
|
+
day_of_week: 1,
|
|
10164
|
+
custom_date: "",
|
|
10165
|
+
next_assignee_id: ""
|
|
10166
|
+
});
|
|
9927
10167
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9928
10168
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
9929
10169
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -9959,6 +10199,14 @@ function QuestDetailsPanel({
|
|
|
9959
10199
|
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
9960
10200
|
setReviewStack((node == null ? void 0 : node.reviewStack) || []);
|
|
9961
10201
|
setTimeline((node == null ? void 0 : node.timeline) || []);
|
|
10202
|
+
setQuestDate((node == null ? void 0 : node.Date) || null);
|
|
10203
|
+
setRecurrenceConfig((node == null ? void 0 : node.recurrence_config) || {
|
|
10204
|
+
enabled: false,
|
|
10205
|
+
type: "daily",
|
|
10206
|
+
day_of_week: 1,
|
|
10207
|
+
custom_date: "",
|
|
10208
|
+
next_assignee_id: ""
|
|
10209
|
+
});
|
|
9962
10210
|
setHasUnsavedChanges(false);
|
|
9963
10211
|
}
|
|
9964
10212
|
}, [node]);
|
|
@@ -10054,6 +10302,7 @@ function QuestDetailsPanel({
|
|
|
10054
10302
|
setIsSaving(false);
|
|
10055
10303
|
}
|
|
10056
10304
|
};
|
|
10305
|
+
const filteredCustomProps = customProps.filter((p) => p.key !== "Date" && p.key !== "Data");
|
|
10057
10306
|
const handleAddTimelineNote = async () => {
|
|
10058
10307
|
if (!noteText.trim() && noteLinks.length === 0 && noteImages.length === 0 || isSaving) return;
|
|
10059
10308
|
setIsSaving(true);
|
|
@@ -10210,6 +10459,7 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10210
10459
|
const currentTimeline = overrides.timeline !== void 0 ? overrides.timeline : timeline;
|
|
10211
10460
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
10212
10461
|
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
10462
|
+
const currentRecurrenceConfig = overrides.recurrenceConfig !== void 0 ? overrides.recurrenceConfig : recurrenceConfig;
|
|
10213
10463
|
if (!keepOpen && !hasUnsavedChanges) {
|
|
10214
10464
|
onClose();
|
|
10215
10465
|
return;
|
|
@@ -10233,11 +10483,13 @@ ${noteText}` : noteText : entry.notes,
|
|
|
10233
10483
|
status: currentStatus,
|
|
10234
10484
|
assignee_id: currentAssigneeId || null,
|
|
10235
10485
|
size,
|
|
10236
|
-
description: currentDescription,
|
|
10486
|
+
description: currentDescription.trim(),
|
|
10237
10487
|
description_sections: processedSections,
|
|
10488
|
+
intensity,
|
|
10489
|
+
recurrence_config: currentRecurrenceConfig,
|
|
10490
|
+
Date: questDate,
|
|
10238
10491
|
useImageAsTexture: false,
|
|
10239
10492
|
textureImageUrl: null,
|
|
10240
|
-
intensity,
|
|
10241
10493
|
is_quest: true,
|
|
10242
10494
|
reviewStack: currentReviewStack,
|
|
10243
10495
|
timeline: currentTimeline,
|
|
@@ -12612,7 +12864,7 @@ function XViewScene({
|
|
|
12612
12864
|
}
|
|
12613
12865
|
}
|
|
12614
12866
|
Object.values(nodeObjects).forEach((mesh) => {
|
|
12615
|
-
const oldLabel = mesh.getObjectByName("timelineLabel");
|
|
12867
|
+
const oldLabel = mesh.getObjectByName("timelineLabel") || mesh.getObjectByName("questDateLabel");
|
|
12616
12868
|
if (oldLabel) {
|
|
12617
12869
|
mesh.remove(oldLabel);
|
|
12618
12870
|
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
@@ -13045,8 +13297,16 @@ function XViewScene({
|
|
|
13045
13297
|
);
|
|
13046
13298
|
const handleActivateQuestLens = useCallback4(({ assigneeId, status: status2 }) => {
|
|
13047
13299
|
var _a2;
|
|
13048
|
-
const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
|
|
13300
|
+
const { nodeObjects, tweenGroup, graphGroup, timelineIntervalsGroup } = stateRef.current;
|
|
13049
13301
|
if (!nodeObjects || !tweenGroup || !graphGroup) return;
|
|
13302
|
+
Object.values(nodeObjects).forEach((mesh) => {
|
|
13303
|
+
const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
|
|
13304
|
+
if (oldLabel) {
|
|
13305
|
+
mesh.remove(oldLabel);
|
|
13306
|
+
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
13307
|
+
oldLabel.material.dispose();
|
|
13308
|
+
}
|
|
13309
|
+
});
|
|
13050
13310
|
const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
|
|
13051
13311
|
const filteredQuests = allQuests.filter((q) => {
|
|
13052
13312
|
const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
|
|
@@ -13068,6 +13328,60 @@ function XViewScene({
|
|
|
13068
13328
|
questsByStatus[q.status].push(q);
|
|
13069
13329
|
}
|
|
13070
13330
|
});
|
|
13331
|
+
const parseDate = (str) => {
|
|
13332
|
+
if (!str) return null;
|
|
13333
|
+
const parts = str.split("/");
|
|
13334
|
+
if (parts.length === 3) {
|
|
13335
|
+
const day = parseInt(parts[0], 10);
|
|
13336
|
+
const month = parseInt(parts[1], 10) - 1;
|
|
13337
|
+
const year = parseInt(parts[2], 10);
|
|
13338
|
+
if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
|
|
13339
|
+
return new Date(year, month, day);
|
|
13340
|
+
}
|
|
13341
|
+
}
|
|
13342
|
+
return null;
|
|
13343
|
+
};
|
|
13344
|
+
const timePoints = /* @__PURE__ */ new Set();
|
|
13345
|
+
const questTimeInfos = /* @__PURE__ */ new Map();
|
|
13346
|
+
filteredQuests.forEach((q) => {
|
|
13347
|
+
const dateProp = q.Date;
|
|
13348
|
+
let info = { isUndated: true, label: "" };
|
|
13349
|
+
if (dateProp) {
|
|
13350
|
+
if (dateProp.date) {
|
|
13351
|
+
const d = parseDate(dateProp.date);
|
|
13352
|
+
if (d) {
|
|
13353
|
+
info = { startDate: d, endDate: d, label: dateProp.date, isUndated: false };
|
|
13354
|
+
timePoints.add(d.getTime());
|
|
13355
|
+
}
|
|
13356
|
+
} else if (dateProp.year) {
|
|
13357
|
+
const y = parseInt(dateProp.year, 10);
|
|
13358
|
+
if (!isNaN(y)) {
|
|
13359
|
+
const d = new Date(y, 0, 1);
|
|
13360
|
+
info = { startDate: d, endDate: d, label: String(y), isUndated: false };
|
|
13361
|
+
timePoints.add(d.getTime());
|
|
13362
|
+
}
|
|
13363
|
+
} else if (dateProp.date_interval && dateProp.date_interval.start) {
|
|
13364
|
+
const sY = parseInt(dateProp.date_interval.start, 10);
|
|
13365
|
+
const eY = parseInt(dateProp.date_interval.end, 10) || sY;
|
|
13366
|
+
if (!isNaN(sY)) {
|
|
13367
|
+
const sd = new Date(sY, 0, 1);
|
|
13368
|
+
const ed = new Date(eY, 11, 31);
|
|
13369
|
+
info = { startDate: sd, endDate: ed, label: `${sY}-${eY}`, isUndated: false };
|
|
13370
|
+
timePoints.add(sd.getTime());
|
|
13371
|
+
timePoints.add(ed.getTime());
|
|
13372
|
+
}
|
|
13373
|
+
}
|
|
13374
|
+
}
|
|
13375
|
+
questTimeInfos.set(String(q.id), info);
|
|
13376
|
+
});
|
|
13377
|
+
const sortedTimePoints = Array.from(timePoints).sort((a, b) => a - b);
|
|
13378
|
+
const timeToYMap = /* @__PURE__ */ new Map();
|
|
13379
|
+
if (sortedTimePoints.length > 0) {
|
|
13380
|
+
const maxIdx = sortedTimePoints.length - 1;
|
|
13381
|
+
sortedTimePoints.forEach((t, i) => {
|
|
13382
|
+
timeToYMap.set(t, (i - maxIdx) * (QUEST_LENS_ROW_SPACING || 30));
|
|
13383
|
+
});
|
|
13384
|
+
}
|
|
13071
13385
|
const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
|
|
13072
13386
|
Object.keys(nodeObjects).forEach((id) => {
|
|
13073
13387
|
const mesh = nodeObjects[id];
|
|
@@ -13104,10 +13418,23 @@ function XViewScene({
|
|
|
13104
13418
|
if (!mesh) {
|
|
13105
13419
|
mesh = addOrUpdateNodeMesh(q, new THREE3.Vector3(colX, 150, 0), true);
|
|
13106
13420
|
}
|
|
13107
|
-
const
|
|
13421
|
+
const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
|
|
13422
|
+
let targetY;
|
|
13423
|
+
if (!timeInfo.isUndated) {
|
|
13424
|
+
targetY = timeToYMap.get(timeInfo.startDate.getTime());
|
|
13425
|
+
} else {
|
|
13426
|
+
const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
|
|
13427
|
+
targetY = -80 - rowIndex * (QUEST_LENS_ROW_SPACING || 30) - undatedOffset;
|
|
13428
|
+
}
|
|
13108
13429
|
const lensTween = new Tween2(mesh.position).to({ x: colX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
|
|
13109
13430
|
tweenGroup.add(lensTween);
|
|
13110
13431
|
lensTween.start();
|
|
13432
|
+
if (!timeInfo.isUndated && timeInfo.label) {
|
|
13433
|
+
const dateSprite = createTextSprite(timeInfo.label, 36);
|
|
13434
|
+
dateSprite.name = "questDateLabel";
|
|
13435
|
+
dateSprite.position.set(0, 3.5, 0);
|
|
13436
|
+
mesh.add(dateSprite);
|
|
13437
|
+
}
|
|
13111
13438
|
if (mesh.userData.labelObject) {
|
|
13112
13439
|
const labelTargetPos = new THREE3.Vector3(colX, targetY, 0).add(
|
|
13113
13440
|
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.39",
|
|
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",
|