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 enum
pull/450/head
Alex van Andel 2021-08-14 17:03:50 +00:00
parent 3a5e7dd61c
commit 252a329f09
4 changed files with 30 additions and 45 deletions

View File

@ -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;
}

View File

@ -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"

View File

@ -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>

View File

@ -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
} }