Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task: Edit Single Text Field #1731

Merged
merged 40 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6023bcd
task: added component for new field form
finnar-bin Jan 10, 2023
ad8b4f2
task: Add back to fields list function
finnar-bin Jan 10, 2023
2d115db
task: fixed dialog content padding
finnar-bin Jan 10, 2023
87e3e97
task: added option for field icon custom sizes
finnar-bin Jan 10, 2023
97ce34a
task: created helper function to find out if first letter is a vowel
finnar-bin Jan 10, 2023
b4afefe
task: moved components to views folders
finnar-bin Jan 10, 2023
abc2697
task: added tabs and dialog actions
finnar-bin Jan 10, 2023
4ad8257
task: added tooltip show delay
finnar-bin Jan 10, 2023
e4ba914
task: add field filter logic
finnar-bin Jan 10, 2023
33d951b
task: moved divider color to theme, modal render handled by condition…
finnar-bin Jan 11, 2023
b80e430
Merge branch 'feature/schema' of github.com:zesty-io/manager-ui into …
finnar-bin Jan 11, 2023
36f0d89
task: added single text creation fields
finnar-bin Jan 11, 2023
619d8d1
Merge branch 'feature/schema' of github.com:zesty-io/manager-ui into …
finnar-bin Jan 12, 2023
06ba87d
task: replaced vh padding and added maxHeight
finnar-bin Jan 12, 2023
4135a46
task: field sort and icon update
finnar-bin Jan 12, 2023
7735240
task: spacing updates
finnar-bin Jan 12, 2023
d27a8a4
task: moved search fields to title bar
finnar-bin Jan 12, 2023
723a72d
task: fixed dialog content padding
finnar-bin Jan 12, 2023
8f937c3
Merge branch 'task/field-creation-tabs' of github.com:zesty-io/manage…
finnar-bin Jan 12, 2023
e705af6
task: add logic to get field data
finnar-bin Jan 12, 2023
d5f0465
task: added logic to show/hide validation error msg
finnar-bin Jan 12, 2023
f0b0a7e
task: integrate rtk query for creating a field
finnar-bin Jan 13, 2023
2759271
task: fixed fields list not refreshing on new field add
finnar-bin Jan 13, 2023
b3d5ffd
task: add logic to prevent re-using field name
finnar-bin Jan 13, 2023
b518421
task: close modal on field creation successful
finnar-bin Jan 13, 2023
8d4654e
task: added comments
finnar-bin Jan 13, 2023
a35b0fd
task: resolved conflicts
finnar-bin Jan 13, 2023
5c26630
task: added menu dropdown
finnar-bin Jan 16, 2023
bff5281
Merge branch 'feature/schema' of github.com:zesty-io/manager-ui into …
finnar-bin Jan 16, 2023
2de217c
task: add edit field modal
finnar-bin Jan 16, 2023
4a4d3ea
task: move fields query to modal and added get field data rtk query
finnar-bin Jan 16, 2023
cd596e0
task: pre-fill form value and added new types
finnar-bin Jan 16, 2023
456bd0b
task: make sure model header tabs are loaded properly when edit field…
finnar-bin Jan 16, 2023
255a9c0
task: integrate rtk query to update field & cache invalidation
finnar-bin Jan 16, 2023
57e6813
task: dynamic modal header text
finnar-bin Jan 16, 2023
280329c
task: added loading indicator
finnar-bin Jan 16, 2023
956409b
task: added loading button
finnar-bin Jan 16, 2023
d3c6378
task: update comment
finnar-bin Jan 16, 2023
9b73ee2
task: use direct url push when closing edit modal
finnar-bin Jan 17, 2023
1390a33
task: removed get field data rtk query
finnar-bin Jan 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
InputBase,
} from "@mui/material";

import { FormValue } from "./views/FieldForm";

type FieldType = "input" | "checkbox" | "dropdown";
export interface InputField {
name: string;
Expand All @@ -22,18 +24,14 @@ export interface InputField {
interface Props {
fieldConfig: InputField;
errorMsg?: string;
onDataChange: ({
name,
value,
}: {
name: string;
value: string | boolean;
}) => void;
onDataChange: ({ name, value }: { name: string; value: FormValue }) => void;
prefillData?: FormValue;
}
export const FieldFormInput = ({
fieldConfig,
errorMsg,
onDataChange,
prefillData,
}: Props) => {
return (
<Box mb={2.5}>
Expand Down Expand Up @@ -78,6 +76,7 @@ export const FieldFormInput = ({
value: e.target.value,
});
}}
value={prefillData}
/>
{errorMsg && (
<Typography mt={0.5} variant="body2" color="error.dark">
Expand All @@ -100,6 +99,7 @@ export const FieldFormInput = ({
value: e.target.checked,
});
}}
checked={Boolean(prefillData)}
/>
}
label={
Expand Down
32 changes: 27 additions & 5 deletions src/apps/schema/src/appRevamp/components/AddFieldModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { Dispatch, SetStateAction, useState } from "react";
import { Dispatch, SetStateAction, useState, useMemo } from "react";
import { useParams } from "react-router";
import { Dialog } from "@mui/material";

import { FieldSelection } from "./views/FieldSelection";
import { FieldForm } from "./views/FieldForm";
import { ContentModelField } from "../../../../../../shell/services/types";
import { useGetContentModelFieldsQuery } from "../../../../../../shell/services/instance";

type Params = {
id: string;
fieldId: string;
};
export type ViewMode = "fields_list" | "new_field" | "update_field";
interface Props {
onModalClose: Dispatch<SetStateAction<boolean>>;
fields: ContentModelField[];
mode: ViewMode;
}
export const AddFieldModal = ({ onModalClose, fields }: Props) => {
const [viewMode, setViewMode] = useState<ViewMode>("fields_list");
export const AddFieldModal = ({ onModalClose, mode }: Props) => {
const [viewMode, setViewMode] = useState<ViewMode>(mode);
const [selectedField, setSelectedField] = useState({
fieldType: "",
fieldName: "",
});
const params = useParams<Params>();
const { id, fieldId } = params;
const { data: fields } = useGetContentModelFieldsQuery(id);

const fieldData = useMemo(() => {
return fields?.find((field) => field.ZUID === fieldId);
}, [fieldId, fields]);

const handleFieldClick = (fieldType: string, fieldName: string) => {
setViewMode("new_field");
Expand Down Expand Up @@ -57,6 +69,16 @@ export const AddFieldModal = ({ onModalClose, fields }: Props) => {
onFieldCreationSuccesssful={() => onModalClose(false)}
/>
)}
{viewMode === "update_field" && (
<FieldForm
fields={fields}
type={fieldData?.datatype}
name={fieldData?.label}
onModalClose={() => onModalClose(false)}
onFieldCreationSuccesssful={() => onModalClose(false)}
fieldData={fieldData}
/>
)}
</Dialog>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {
Tabs,
Tab,
Button,
CircularProgress,
} from "@mui/material";
import { snakeCase } from "lodash";
import LoadingButton from "@mui/lab/LoadingButton";
import { snakeCase, isEmpty } from "lodash";

import CloseIcon from "@mui/icons-material/Close";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
Expand All @@ -20,8 +22,15 @@ import AddRoundedIcon from "@mui/icons-material/AddRounded";
import { FieldIcon } from "../../Field/FieldIcon";
import { stringStartsWithVowel } from "../../utils";
import { InputField, FieldFormInput } from "../FieldFormInput";
import { useCreateContentModelFieldMutation } from "../../../../../../../shell/services/instance";
import { ContentModelField } from "../../../../../../../shell/services/types";
import {
useCreateContentModelFieldMutation,
useUpdateContentModelFieldMutation,
} from "../../../../../../../shell/services/instance";
import {
ContentModelField,
FieldSettings,
ContentModelFieldValue,
} from "../../../../../../../shell/services/types";

const commonFields: InputField[] = [
{
Expand Down Expand Up @@ -88,8 +97,9 @@ type ActiveTab = "details" | "rules";
type Params = {
id: string;
};
export type FormValue = Exclude<ContentModelFieldValue, FieldSettings>;
interface FormData {
[key: string]: string | boolean;
[key: string]: FormValue;
}
interface Errors {
[key: string]: string;
Expand All @@ -98,9 +108,10 @@ interface Props {
type: string;
name: string;
onModalClose: () => void;
onBackClick: () => void;
onBackClick?: () => void;
fields: ContentModelField[];
onFieldCreationSuccesssful: () => void;
fieldData?: ContentModelField;
}
export const FieldForm = ({
type,
Expand All @@ -109,38 +120,62 @@ export const FieldForm = ({
onBackClick,
fields,
onFieldCreationSuccesssful,
fieldData,
}: Props) => {
const [activeTab, setActiveTab] = useState<ActiveTab>("details");
const [isSubmitClicked, setIsSubmitClicked] = useState(false);
const [errors, setErrors] = useState<Errors>({});
const [formData, setFormData] = useState<FormData>({});
const params = useParams<Params>();
const { id } = params;
const [createContentModelField, { isLoading, isSuccess }] =
useCreateContentModelFieldMutation();
const [
createContentModelField,
{ isLoading: isCreatingField, isSuccess: isFieldCreated },
] = useCreateContentModelFieldMutation();
const [
updateContentModelField,
{ isLoading: isUpdatingField, isSuccess: isFieldUpdated },
] = useUpdateContentModelFieldMutation();
const isUpdateField = !isEmpty(fieldData);

useEffect(() => {
let formFields: { [key: string]: string | boolean } = {};
let formFields: { [key: string]: FormValue } = {};
let errors: { [key: string]: string } = {};

formConfig[type].forEach((field) => {
formFields[field.name] = field.type === "checkbox" ? false : "";
formConfig[type]?.forEach((field) => {
if (isUpdateField) {
if (field.name === "list") {
formFields[field.name] = fieldData.settings[field.name];
} else {
formFields[field.name] = fieldData[field.name] as FormValue;
}

if (field.required) {
errors[field.name] = "This field is required";
// Pre-fill error messages based on content
if (field.required) {
errors[field.name] = isEmpty(fieldData[field.name])
? "This field is required"
: "";
}
} else {
formFields[field.name] = field.type === "checkbox" ? false : "";

// Pre-fill required fields error msgs
if (field.required) {
errors[field.name] = "This field is required";
}
}
});

setFormData(formFields);
setErrors(errors);
}, [type]);
}, [type, fieldData]);

useEffect(() => {
// TODO: Field creation flow is not yet completed, closing modal on success for now
if (isSuccess) {
if (isFieldCreated || isFieldUpdated) {
onFieldCreationSuccesssful();
}
}, [isSuccess]);
}, [isFieldCreated, isFieldUpdated]);

const handleSubmitForm = () => {
setIsSubmitClicked(true);
Expand All @@ -163,10 +198,23 @@ export const FieldForm = ({
settings: {
list: formData.list as boolean,
},
sort: fields?.length, // Just use the length since sort starts at 0
sort: isUpdateField ? fieldData.sort : fields?.length, // Just use the length since sort starts at 0
};

createContentModelField({ modelZUID: id, body });
if (isUpdateField) {
const updateBody: ContentModelField = {
...fieldData,
...body,
};

updateContentModelField({
modelZUID: id,
fieldZUID: fieldData.ZUID,
body: updateBody,
});
} else {
createContentModelField({ modelZUID: id, body });
}
};

const handleFieldDataChange = ({
Expand All @@ -185,9 +233,17 @@ export const FieldForm = ({
let errorMsg = value ? "" : "This field is required";

if (value && name === "name") {
errorMsg = currFieldNames.includes(value as string)
? "Field name already exists"
: "";
if (isUpdateField) {
// Re-using its original name is fine when updating a field
errorMsg =
currFieldNames.includes(value as string) && value !== fieldData.name
? "Field name already exists"
: "";
} else {
errorMsg = currFieldNames.includes(value as string)
? "Field name already exists"
: "";
}
}

if (name in errors) {
Expand Down Expand Up @@ -217,9 +273,11 @@ export const FieldForm = ({
pb={0.5}
>
<Box display="flex" alignItems="center">
<IconButton size="small" onClick={onBackClick}>
<ArrowBackIcon />
</IconButton>
{!isUpdateField && (
<IconButton size="small" onClick={onBackClick}>
<ArrowBackIcon />
</IconButton>
)}
<Box px={1.5}>
<FieldIcon
type={type}
Expand All @@ -228,7 +286,7 @@ export const FieldForm = ({
fontSize="16px"
/>
</Box>
{headerText}
{isUpdateField ? fieldData.label : headerText}
</Box>
<IconButton size="small" onClick={onModalClose}>
<CloseIcon />
Expand All @@ -251,13 +309,14 @@ export const FieldForm = ({
>
{activeTab === "details" && (
<>
{formConfig[type].map((fieldConfig, index) => {
{formConfig[type]?.map((fieldConfig, index) => {
return (
<FieldFormInput
key={index}
fieldConfig={fieldConfig}
onDataChange={handleFieldDataChange}
errorMsg={isSubmitClicked && errors[fieldConfig.name]}
prefillData={formData[fieldConfig.name]}
/>
);
})}
Expand Down Expand Up @@ -290,13 +349,13 @@ export const FieldForm = ({
>
Add another field
</Button>
<Button
disabled={isLoading}
<LoadingButton
loading={isCreatingField || isUpdatingField}
onClick={handleSubmitForm}
variant="contained"
>
Done
</Button>
</LoadingButton>
</Box>
</DialogActions>
</>
Expand Down
Loading