Skip to content

Commit

Permalink
fix(page type): Convert to page type should create slice zone for mai…
Browse files Browse the repository at this point in the history
…n tab if necessary
  • Loading branch information
xrutayisire committed Oct 17, 2023
1 parent eada429 commit 708f67e
Show file tree
Hide file tree
Showing 3 changed files with 369 additions and 5 deletions.
118 changes: 118 additions & 0 deletions packages/slice-machine/src/domain/CustomTypeModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import {
CustomType,
DynamicSection,
DynamicSlicesConfig,
} from "@prismicio/types-internal/lib/customtypes";

export function getSectionEntries(
customType: CustomType
): [string, DynamicSection][] {
return Object.entries(customType.json);
}

export function getMainSectionEntry(
customType: CustomType
): [string, DynamicSection] | undefined {
// Currently we cannot rely on the name of the main section
// since it's possible to rename it
const sections = getSectionEntries(customType);
return sections[0];
}

export function getSection(
customType: CustomType,
sectionId: string
): DynamicSection | undefined {
return customType.json[sectionId];
}

export function getSectionSliceZoneConfig(
customType: CustomType,
sectionId: string
): DynamicSlicesConfig | undefined {
const section = getSection(customType, sectionId);

if (section === undefined) {
return undefined;
}

// In Slice Machine we currently only support one slice zone per section
// so we retrieve the first one
const maybeSliceZone = Object.values(section).find(
(value) => value.type === "Slices"
);

return maybeSliceZone?.config ?? undefined;
}

export function findAvailableSectionSlicesKey(
customType: CustomType,
sectionId: string
): string {
const sectionsEntries = getSectionEntries(customType);
const sectionIndex = sectionsEntries.findIndex(([key]) => key === sectionId);

const existingKeys = sectionsEntries.flatMap(([_, section]) =>
Object.keys(section).filter((key) => section[key].type === "Slices")
);

let i = sectionIndex;
let proposedKey;
do {
proposedKey = `slices${i !== 0 ? i.toString() : ""}`;
i++;
} while (existingKeys.includes(proposedKey));

return proposedKey;
}

export function createSectionSliceZone(
customType: CustomType,
sectionId: string
): CustomType {
const maybeSectionSliceZoneConfig = getSectionSliceZoneConfig(
customType,
sectionId
);

// If the section already has a slice zone, return the custom type as is
if (maybeSectionSliceZoneConfig) {
return customType;
}

// Get the next available key for the slice zone
const availableSectionSlicesKey = findAvailableSectionSlicesKey(
customType,
sectionId
);

return {
...customType,
json: {
...customType.json,
[sectionId]: {
...customType.json[sectionId],
[availableSectionSlicesKey]: {
type: "Slices",
fieldset: "Slice Zone",
},
},
},
};
}

export function convertToPageType(customType: CustomType): CustomType {
let newCustomType: CustomType = {
...customType,
format: "page",
};

// Create the slice zone for the main section if it doesn't exist
const mainSectionEntry = getMainSectionEntry(customType);
if (mainSectionEntry) {
const [mainSectionKey] = mainSectionEntry;
newCustomType = createSectionSliceZone(newCustomType, mainSectionKey);
}

return newCustomType;
}
247 changes: 247 additions & 0 deletions packages/slice-machine/src/domain/__tests__/CustomTypeModel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import { describe, expect } from "vitest";

import {
CustomType,
DynamicSection,
} from "@prismicio/types-internal/lib/customtypes";

import * as CustomTypeModel from "../CustomTypeModel";

describe("CustomTypeModel test suite", () => {
const mainSection: DynamicSection = {
uid: {
config: {
label: "MainSectionField",
},
type: "UID",
},
slices: {
type: "Slices",
fieldset: "Slice Zone",
config: {
choices: {
hero_banner: {
type: "SharedSlice",
},
promo_section_image_tiles: {
type: "SharedSlice",
},
},
},
},
};
const anotherSection: DynamicSection = {
uid: {
config: {
label: "AnotherSectionField",
},
type: "UID",
},
};
const mockCustomType: CustomType = {
format: "custom",
id: "id",
json: {
mainSection,
anotherSection,
},
label: "lama",
repeatable: true,
status: true,
};

it("getSectionEntries should return the sections entries", () => {
expect(CustomTypeModel.getSectionEntries(mockCustomType)).toEqual([
["mainSection", mainSection],
["anotherSection", anotherSection],
]);
});

it("getSectionEntries should return an empty array if there are no sections", () => {
expect(
CustomTypeModel.getSectionEntries({
...mockCustomType,
json: {},
})
).toEqual([]);
});

it("getMainSectionEntry should return the first section even if not named Main", () => {
expect(CustomTypeModel.getMainSectionEntry(mockCustomType)).toEqual([
"mainSection",
mainSection,
]);
});

it("getMainSectionEntry should return undefined if there is are sections", () => {
expect(
CustomTypeModel.getMainSectionEntry({
...mockCustomType,
json: {},
})
).toEqual(undefined);
});

it("getSection should return the section matching the key", () => {
expect(
CustomTypeModel.getSection(mockCustomType, "anotherSection")
).toEqual(anotherSection);
});

it("getSection should return undefined if there are no sections", () => {
expect(
CustomTypeModel.getSection(
{
...mockCustomType,
json: {},
},
"mainSection"
)
).toEqual(undefined);
});

it("getSectionSliceZoneConfig should return the config of the given section", () => {
expect(
CustomTypeModel.getSectionSliceZoneConfig(mockCustomType, "mainSection")
).toEqual({
choices: {
hero_banner: {
type: "SharedSlice",
},
promo_section_image_tiles: {
type: "SharedSlice",
},
},
});
});

it("getSectionSliceZoneConfig should return undefined if there are no sections", () => {
expect(
CustomTypeModel.getSectionSliceZoneConfig(
{
...mockCustomType,
json: {},
},
"mainSection"
)
).toEqual(undefined);
});

it("findAvailableSectionSlicesKey should return 'slices'", () => {
expect(
CustomTypeModel.findAvailableSectionSlicesKey(
{
...mockCustomType,
json: {
anotherSection: {},
},
},
"anotherSection"
)
).toEqual("slices");
});

it("findAvailableSectionSlicesKey should return 'slices1'", () => {
expect(
CustomTypeModel.findAvailableSectionSlicesKey(
mockCustomType,
"anotherSection"
)
).toEqual("slices1");
});

it("findAvailableSectionSlicesKey should return 'slices2'", () => {
expect(
CustomTypeModel.findAvailableSectionSlicesKey(
{
...mockCustomType,
json: {
mainSection,
SecondSection: {
slices1: {
type: "Slices",
},
},
anotherSection,
},
},
"anotherSection"
)
).toEqual("slices2");
});

it("findAvailableSectionSlicesKey should return 'slices3'", () => {
expect(
CustomTypeModel.findAvailableSectionSlicesKey(
{
...mockCustomType,
json: {
mainSection,
SecondSection: {
slices2: {
type: "Slices",
},
},
anotherSection,
},
},
"anotherSection"
)
).toEqual("slices3");
});

it("createSectionSliceZone should return the given custom type with a slice zone for given section", () => {
expect(
CustomTypeModel.createSectionSliceZone(mockCustomType, "anotherSection")
).toEqual({
...mockCustomType,
json: {
...mockCustomType.json,
anotherSection: {
...mockCustomType.json.anotherSection,
slices1: {
type: "Slices",
fieldset: "Slice Zone",
},
},
},
});
});

it("createSectionSliceZone should return the same custom type if slice zone already exist for given section", () => {
expect(
CustomTypeModel.createSectionSliceZone(mockCustomType, "mainSection")
).toEqual(mockCustomType);
});

it("convertToPageType should convert the given custom type", () => {
expect(CustomTypeModel.convertToPageType(mockCustomType)).toEqual({
...mockCustomType,
format: "page",
});
});

it("convertToPageType should convert the given custom type with a slice zone for Main section when it doesn't exist", () => {
expect(
CustomTypeModel.convertToPageType({
...mockCustomType,
json: {
mainSection: {},
anotherSection,
},
})
).toEqual({
...mockCustomType,
json: {
mainSection: {
slices: {
type: "Slices",
fieldset: "Slice Zone",
},
},
anotherSection,
},
format: "page",
});
});
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { toast } from "react-toastify";

import { CustomType } from "@prismicio/types-internal/lib/customtypes";

import { CustomTypeFormat } from "@slicemachine/manager";
import { convertToPageType } from "@src/domain/CustomTypeModel";
import { managerClient } from "@src/managerClient";

import { CUSTOM_TYPES_MESSAGES } from "../customTypesMessages";

export async function convertCustomToPageType(
Expand All @@ -13,10 +15,7 @@ export async function convertCustomToPageType(
CUSTOM_TYPES_MESSAGES[customType.format as CustomTypeFormat];

try {
const newCustomType: CustomType = {
...customType,
format: "page",
};
const newCustomType = convertToPageType(customType);
await managerClient.customTypes.updateCustomType({
model: newCustomType,
});
Expand Down

0 comments on commit 708f67e

Please sign in to comment.