Fixed issues relating to custom-inputs
* Don't duplicate custom input when editing before db persist * Remove correct custom input during delete pre db persist (id undefined) * Moved typings to prisma, keeping backwards compatibility with @map * Updated all usages of the enumpull/450/head
parent
3a5e7dd61c
commit
252a329f09
|
@ -1,13 +0,0 @@
|
||||||
export enum EventTypeCustomInputType {
|
|
||||||
Text = 'text',
|
|
||||||
TextLong = 'textLong',
|
|
||||||
Number = 'number',
|
|
||||||
Bool = 'bool',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EventTypeCustomInput {
|
|
||||||
id?: number;
|
|
||||||
type: EventTypeCustomInputType;
|
|
||||||
label: string;
|
|
||||||
required: boolean;
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { CalendarIcon, ClockIcon, ExclamationIcon, LocationMarkerIcon } from "@heroicons/react/solid";
|
import { CalendarIcon, ClockIcon, ExclamationIcon, LocationMarkerIcon } from "@heroicons/react/solid";
|
||||||
import prisma, { whereAndSelect } from "../../lib/prisma";
|
import prisma, { whereAndSelect } from "../../lib/prisma";
|
||||||
|
import { EventTypeCustomInputType } from "@prisma/client";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
@ -13,7 +14,6 @@ import PhoneInput from "react-phone-number-input";
|
||||||
import { LocationType } from "../../lib/location";
|
import { LocationType } from "../../lib/location";
|
||||||
import Avatar from "../../components/Avatar";
|
import Avatar from "../../components/Avatar";
|
||||||
import Button from "../../components/ui/Button";
|
import Button from "../../components/ui/Button";
|
||||||
import { EventTypeCustomInputType } from "../../lib/eventTypeInput";
|
|
||||||
import Theme from "@components/Theme";
|
import Theme from "@components/Theme";
|
||||||
import { ReactMultiEmail } from "react-multi-email";
|
import { ReactMultiEmail } from "react-multi-email";
|
||||||
import "react-multi-email/style.css";
|
import "react-multi-email/style.css";
|
||||||
|
@ -71,7 +71,7 @@ export default function Book(props: any): JSX.Element {
|
||||||
.map((input) => {
|
.map((input) => {
|
||||||
const data = event.target["custom_" + input.id];
|
const data = event.target["custom_" + input.id];
|
||||||
if (data) {
|
if (data) {
|
||||||
if (input.type === EventTypeCustomInputType.Bool) {
|
if (input.type === EventTypeCustomInputType.BOOL) {
|
||||||
return input.label + "\n" + (data.checked ? "Yes" : "No");
|
return input.label + "\n" + (data.checked ? "Yes" : "No");
|
||||||
} else {
|
} else {
|
||||||
return input.label + "\n" + data.value;
|
return input.label + "\n" + data.value;
|
||||||
|
@ -273,14 +273,14 @@ export default function Book(props: any): JSX.Element {
|
||||||
.sort((a, b) => a.id - b.id)
|
.sort((a, b) => a.id - b.id)
|
||||||
.map((input) => (
|
.map((input) => (
|
||||||
<div className="mb-4" key={"input-" + input.label.toLowerCase}>
|
<div className="mb-4" key={"input-" + input.label.toLowerCase}>
|
||||||
{input.type !== EventTypeCustomInputType.Bool && (
|
{input.type !== EventTypeCustomInputType.BOOL && (
|
||||||
<label
|
<label
|
||||||
htmlFor={input.label}
|
htmlFor={input.label}
|
||||||
className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||||
{input.label}
|
{input.label}
|
||||||
</label>
|
</label>
|
||||||
)}
|
)}
|
||||||
{input.type === EventTypeCustomInputType.TextLong && (
|
{input.type === EventTypeCustomInputType.TEXTLONG && (
|
||||||
<textarea
|
<textarea
|
||||||
name={"custom_" + input.id}
|
name={"custom_" + input.id}
|
||||||
id={"custom_" + input.id}
|
id={"custom_" + input.id}
|
||||||
|
@ -290,7 +290,7 @@ export default function Book(props: any): JSX.Element {
|
||||||
placeholder=""
|
placeholder=""
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{input.type === EventTypeCustomInputType.Text && (
|
{input.type === EventTypeCustomInputType.TEXT && (
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name={"custom_" + input.id}
|
name={"custom_" + input.id}
|
||||||
|
@ -300,7 +300,7 @@ export default function Book(props: any): JSX.Element {
|
||||||
placeholder=""
|
placeholder=""
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{input.type === EventTypeCustomInputType.Number && (
|
{input.type === EventTypeCustomInputType.NUMBER && (
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
name={"custom_" + input.id}
|
name={"custom_" + input.id}
|
||||||
|
@ -310,7 +310,7 @@ export default function Book(props: any): JSX.Element {
|
||||||
placeholder=""
|
placeholder=""
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{input.type === EventTypeCustomInputType.Bool && (
|
{input.type === EventTypeCustomInputType.BOOL && (
|
||||||
<div className="flex items-center h-5">
|
<div className="flex items-center h-5">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
|
@ -5,13 +5,13 @@ import { useRouter } from "next/router";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import Select, { OptionBase } from "react-select";
|
import Select, { OptionBase } from "react-select";
|
||||||
import prisma from "@lib/prisma";
|
import prisma from "@lib/prisma";
|
||||||
|
import { EventTypeCustomInput, EventTypeCustomInputType } from "@prisma/client";
|
||||||
import { LocationType } from "@lib/location";
|
import { LocationType } from "@lib/location";
|
||||||
import Shell from "@components/Shell";
|
import Shell from "@components/Shell";
|
||||||
import { getSession } from "next-auth/client";
|
import { getSession } from "next-auth/client";
|
||||||
import { Scheduler } from "@components/ui/Scheduler";
|
import { Scheduler } from "@components/ui/Scheduler";
|
||||||
import { Disclosure, RadioGroup } from "@headlessui/react";
|
import { Disclosure, RadioGroup } from "@headlessui/react";
|
||||||
import { PhoneIcon, XIcon } from "@heroicons/react/outline";
|
import { PhoneIcon, XIcon } from "@heroicons/react/outline";
|
||||||
import { EventTypeCustomInput, EventTypeCustomInputType } from "@lib/eventTypeInput";
|
|
||||||
import {
|
import {
|
||||||
LocationMarkerIcon,
|
LocationMarkerIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
|
@ -106,10 +106,10 @@ export default function EventTypePage({
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const inputOptions: OptionBase[] = [
|
const inputOptions: OptionBase[] = [
|
||||||
{ value: EventTypeCustomInputType.Text, label: "Text" },
|
{ value: EventTypeCustomInputType.TEXT, label: "Text" },
|
||||||
{ value: EventTypeCustomInputType.TextLong, label: "Multiline Text" },
|
{ value: EventTypeCustomInputType.TEXTLONG, label: "Multiline Text" },
|
||||||
{ value: EventTypeCustomInputType.Number, label: "Number" },
|
{ value: EventTypeCustomInputType.NUMBER, label: "Number" },
|
||||||
{ value: EventTypeCustomInputType.Bool, label: "Checkbox" },
|
{ value: EventTypeCustomInputType.BOOL, label: "Checkbox" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const [DATE_PICKER_ORIENTATION, setDatePickerOrientation] = useState<OrientationShape>("horizontal");
|
const [DATE_PICKER_ORIENTATION, setDatePickerOrientation] = useState<OrientationShape>("horizontal");
|
||||||
|
@ -342,28 +342,19 @@ export default function EventTypePage({
|
||||||
type: e.target.type.value,
|
type: e.target.type.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (e.target.id?.value) {
|
if (selectedCustomInput) {
|
||||||
const index = customInputs.findIndex((inp) => inp.id === +e.target.id?.value);
|
selectedCustomInput.label = customInput.label;
|
||||||
if (index >= 0) {
|
selectedCustomInput.required = customInput.required;
|
||||||
const input = customInputs[index];
|
selectedCustomInput.type = customInput.type;
|
||||||
input.label = customInput.label;
|
|
||||||
input.required = customInput.required;
|
|
||||||
input.type = customInput.type;
|
|
||||||
setCustomInputs(customInputs);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setCustomInputs(customInputs.concat(customInput));
|
setCustomInputs(customInputs.concat(customInput));
|
||||||
}
|
}
|
||||||
closeAddCustomModal();
|
closeAddCustomModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeCustom = (customInput, e) => {
|
const removeCustom = (index: number) => {
|
||||||
e.preventDefault();
|
customInputs.splice(index, 1);
|
||||||
const index = customInputs.findIndex((inp) => inp.id === customInput.id);
|
setCustomInputs([...customInputs]);
|
||||||
if (index >= 0) {
|
|
||||||
customInputs.splice(index, 1);
|
|
||||||
setCustomInputs([...customInputs]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -638,8 +629,8 @@ export default function EventTypePage({
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<ul className="w-96 mt-1">
|
<ul className="w-96 mt-1">
|
||||||
{customInputs.map((customInput) => (
|
{customInputs.map((customInput: EventTypeCustomInput, idx: number) => (
|
||||||
<li key={customInput.label} className="bg-secondary-50 mb-2 p-2 border">
|
<li key={idx} className="bg-secondary-50 mb-2 p-2 border">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -661,7 +652,7 @@ export default function EventTypePage({
|
||||||
className="mr-2 text-sm text-primary-600">
|
className="mr-2 text-sm text-primary-600">
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button onClick={(e) => removeCustom(customInput, e)}>
|
<button type="button" onClick={() => removeCustom(idx)}>
|
||||||
<XIcon className="h-6 w-6 border-l-2 pl-1 hover:text-red-500 " />
|
<XIcon className="h-6 w-6 border-l-2 pl-1 hover:text-red-500 " />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -162,12 +162,19 @@ model SelectedCalendar {
|
||||||
@@id([userId,integration,externalId])
|
@@id([userId,integration,externalId])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EventTypeCustomInputType {
|
||||||
|
TEXT @map("text")
|
||||||
|
TEXTLONG @map("textLong")
|
||||||
|
NUMBER @map("number")
|
||||||
|
BOOL @map("bool")
|
||||||
|
}
|
||||||
|
|
||||||
model EventTypeCustomInput {
|
model EventTypeCustomInput {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
eventTypeId Int
|
eventTypeId Int
|
||||||
eventType EventType @relation(fields: [eventTypeId], references: [id])
|
eventType EventType @relation(fields: [eventTypeId], references: [id])
|
||||||
label String
|
label String
|
||||||
type String
|
type EventTypeCustomInputType
|
||||||
required Boolean
|
required Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue