feat: dispositivos e ajustes de csat e relatórios
This commit is contained in:
parent
25d2a9b062
commit
e0ef66555d
86 changed files with 5811 additions and 992 deletions
|
|
@ -38,8 +38,8 @@ function validateOptions(type: FieldType, options: { value: string; label: strin
|
|||
}
|
||||
|
||||
export const list = query({
|
||||
args: { tenantId: v.string(), viewerId: v.id("users") },
|
||||
handler: async (ctx, { tenantId, viewerId }) => {
|
||||
args: { tenantId: v.string(), viewerId: v.id("users"), scope: v.optional(v.string()) },
|
||||
handler: async (ctx, { tenantId, viewerId, scope }) => {
|
||||
await requireAdmin(ctx, viewerId, tenantId);
|
||||
const fields = await ctx.db
|
||||
.query("ticketFields")
|
||||
|
|
@ -47,6 +47,12 @@ export const list = query({
|
|||
.collect();
|
||||
|
||||
return fields
|
||||
.filter((field) => {
|
||||
if (!scope) return true;
|
||||
const fieldScope = (field.scope ?? "all").trim();
|
||||
if (fieldScope === "all" || fieldScope.length === 0) return true;
|
||||
return fieldScope === scope;
|
||||
})
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((field) => ({
|
||||
id: field._id,
|
||||
|
|
@ -57,6 +63,7 @@ export const list = query({
|
|||
required: field.required,
|
||||
options: field.options ?? [],
|
||||
order: field.order,
|
||||
scope: field.scope ?? "all",
|
||||
createdAt: field.createdAt,
|
||||
updatedAt: field.updatedAt,
|
||||
}));
|
||||
|
|
@ -64,8 +71,8 @@ export const list = query({
|
|||
});
|
||||
|
||||
export const listForTenant = query({
|
||||
args: { tenantId: v.string(), viewerId: v.id("users") },
|
||||
handler: async (ctx, { tenantId, viewerId }) => {
|
||||
args: { tenantId: v.string(), viewerId: v.id("users"), scope: v.optional(v.string()) },
|
||||
handler: async (ctx, { tenantId, viewerId, scope }) => {
|
||||
await requireUser(ctx, viewerId, tenantId);
|
||||
const fields = await ctx.db
|
||||
.query("ticketFields")
|
||||
|
|
@ -73,6 +80,12 @@ export const listForTenant = query({
|
|||
.collect();
|
||||
|
||||
return fields
|
||||
.filter((field) => {
|
||||
if (!scope) return true;
|
||||
const fieldScope = (field.scope ?? "all").trim();
|
||||
if (fieldScope === "all" || fieldScope.length === 0) return true;
|
||||
return fieldScope === scope;
|
||||
})
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((field) => ({
|
||||
id: field._id,
|
||||
|
|
@ -83,6 +96,7 @@ export const listForTenant = query({
|
|||
required: field.required,
|
||||
options: field.options ?? [],
|
||||
order: field.order,
|
||||
scope: field.scope ?? "all",
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
|
@ -103,8 +117,9 @@ export const create = mutation({
|
|||
})
|
||||
)
|
||||
),
|
||||
scope: v.optional(v.string()),
|
||||
},
|
||||
handler: async (ctx, { tenantId, actorId, label, description, type, required, options }) => {
|
||||
handler: async (ctx, { tenantId, actorId, label, description, type, required, options, scope }) => {
|
||||
await requireAdmin(ctx, actorId, tenantId);
|
||||
const normalizedLabel = label.trim();
|
||||
if (normalizedLabel.length < 2) {
|
||||
|
|
@ -116,6 +131,15 @@ export const create = mutation({
|
|||
validateOptions(type as FieldType, options ?? undefined);
|
||||
const key = normalizeKey(normalizedLabel);
|
||||
await ensureUniqueKey(ctx, tenantId, key);
|
||||
const normalizedScope = (() => {
|
||||
const raw = scope?.trim();
|
||||
if (!raw || raw.length === 0) return "all";
|
||||
const safe = raw.toLowerCase();
|
||||
if (!/^[a-z0-9_\-]+$/i.test(safe)) {
|
||||
throw new ConvexError("Escopo inválido para o campo");
|
||||
}
|
||||
return safe;
|
||||
})();
|
||||
|
||||
const existing = await ctx.db
|
||||
.query("ticketFields")
|
||||
|
|
@ -133,6 +157,7 @@ export const create = mutation({
|
|||
required,
|
||||
options,
|
||||
order: maxOrder + 1,
|
||||
scope: normalizedScope,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
|
@ -157,8 +182,9 @@ export const update = mutation({
|
|||
})
|
||||
)
|
||||
),
|
||||
scope: v.optional(v.string()),
|
||||
},
|
||||
handler: async (ctx, { tenantId, fieldId, actorId, label, description, type, required, options }) => {
|
||||
handler: async (ctx, { tenantId, fieldId, actorId, label, description, type, required, options, scope }) => {
|
||||
await requireAdmin(ctx, actorId, tenantId);
|
||||
const field = await ctx.db.get(fieldId);
|
||||
if (!field || field.tenantId !== tenantId) {
|
||||
|
|
@ -173,6 +199,16 @@ export const update = mutation({
|
|||
}
|
||||
validateOptions(type as FieldType, options ?? undefined);
|
||||
|
||||
const normalizedScope = (() => {
|
||||
const raw = scope?.trim();
|
||||
if (!raw || raw.length === 0) return "all";
|
||||
const safe = raw.toLowerCase();
|
||||
if (!/^[a-z0-9_\-]+$/i.test(safe)) {
|
||||
throw new ConvexError("Escopo inválido para o campo");
|
||||
}
|
||||
return safe;
|
||||
})();
|
||||
|
||||
let key = field.key;
|
||||
if (field.label !== normalizedLabel) {
|
||||
key = normalizeKey(normalizedLabel);
|
||||
|
|
@ -186,6 +222,7 @@ export const update = mutation({
|
|||
type,
|
||||
required,
|
||||
options,
|
||||
scope: normalizedScope,
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue