From b18fae3937a33068a29ca1b92b40d41e7713533d Mon Sep 17 00:00:00 2001 From: Mathias Oterhals Myklebust <24361490+mathiazom@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:55:03 +0000 Subject: [PATCH] v3 - custom ordered array input component (#683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(compensations): custom component for fixed order of array input elements * refactor(ValueOrderedArrayOfObjectsInput): OrderedArrayOfObjectsInputProps → ValueOrderedArrayOfObjectsInputProps --- .../ValueOrderedArrayOfObjectsInput.tsx | 29 +++++++++++++++ studio/lib/interfaces/compensations.ts | 36 ++++++++++++++++--- studio/lib/interfaces/global.ts | 5 --- .../compensations/bonusesByLocation.ts | 25 +++++++++++-- .../compensations/salariesByLocation.ts | 28 +++++++++++++-- 5 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 studio/components/ValueOrderedArrayOfObjectsInput.tsx diff --git a/studio/components/ValueOrderedArrayOfObjectsInput.tsx b/studio/components/ValueOrderedArrayOfObjectsInput.tsx new file mode 100644 index 000000000..672fd98a5 --- /dev/null +++ b/studio/components/ValueOrderedArrayOfObjectsInput.tsx @@ -0,0 +1,29 @@ +import { ArrayOfObjectsInputProps, ObjectItem } from "sanity"; + +interface ValueOrderedArrayOfObjectsInputProps + extends ArrayOfObjectsInputProps { + valueCompareFn: (a: ObjectItem, b: ObjectItem) => number; +} + +export default function ValueOrderedArrayOfObjectsInput({ + valueCompareFn, + ...defaultProps +}: ValueOrderedArrayOfObjectsInputProps) { + const orderedMembers = defaultProps.members.toSorted((a, b) => { + // place error items at the end + if (a.kind === "error") { + if (b.kind === "error") { + return 0; + } else { + return 1; + } + } else if (b.kind === "error") { + return -1; + } + return valueCompareFn(a.item.value, b.item.value); + }); + return defaultProps.renderDefault({ + ...defaultProps, + members: orderedMembers, + }); +} diff --git a/studio/lib/interfaces/compensations.ts b/studio/lib/interfaces/compensations.ts index 4b1a0b261..a94bb1fb0 100644 --- a/studio/lib/interfaces/compensations.ts +++ b/studio/lib/interfaces/compensations.ts @@ -1,6 +1,6 @@ -import { PortableTextBlock } from "sanity"; +import { PortableTextBlock, Reference } from "sanity"; -import { Reference, Slug } from "./global"; +import { Slug } from "./global"; export interface Benefit { _type: string; @@ -16,12 +16,26 @@ export interface BenefitsByLocation { } export interface SalariesPage { - _type: string; + _type?: string; _key: string; year: number; salaries: string; } +export const isSalariesPage = (value: unknown): value is SalariesPage => { + return ( + typeof value === "object" && + value !== null && + (!("_type" in value) || typeof value._type === "string") && + "_key" in value && + typeof value._key === "string" && + "year" in value && + typeof value.year === "number" && + "salaries" in value && + typeof value.salaries === "string" + ); +}; + export interface BonusesByLocationPage { _type: string; _key: string; @@ -30,12 +44,26 @@ export interface BonusesByLocationPage { } export interface BonusPage { - _type: string; + _type?: string; _key: string; year: number; bonus: number; } +export const isBonusPage = (value: unknown): value is BonusPage => { + return ( + typeof value === "object" && + value !== null && + (!("_type" in value) || typeof value._type === "string") && + "_key" in value && + typeof value._key === "string" && + "year" in value && + typeof value.year === "number" && + "bonus" in value && + typeof value.bonus === "number" + ); +}; + export interface SalariesByLocation { _key: string; _type: string; diff --git a/studio/lib/interfaces/global.ts b/studio/lib/interfaces/global.ts index 11aed98eb..7b51d3dcb 100644 --- a/studio/lib/interfaces/global.ts +++ b/studio/lib/interfaces/global.ts @@ -3,11 +3,6 @@ export interface Slug { current: string; } -export interface Reference { - _type: "reference"; - _ref: string; -} - export interface DocumentWithSlug { slug: Slug; _updatedAt: string; diff --git a/studio/schemas/objects/compensations/bonusesByLocation.ts b/studio/schemas/objects/compensations/bonusesByLocation.ts index 4f540d54c..f1923e2dd 100644 --- a/studio/schemas/objects/compensations/bonusesByLocation.ts +++ b/studio/schemas/objects/compensations/bonusesByLocation.ts @@ -1,6 +1,7 @@ -import { defineField } from "sanity"; +import { ArrayOfObjectsInputProps, defineField } from "sanity"; -import { BonusPage } from "studio/lib/interfaces/compensations"; +import ValueOrderedArrayOfObjectsInput from "studio/components/ValueOrderedArrayOfObjectsInput"; +import { BonusPage, isBonusPage } from "studio/lib/interfaces/compensations"; import { companyLocationNameID } from "studio/schemas/documents/admin/companyLocation"; import { location, locationID } from "studio/schemas/objects/locations"; @@ -35,6 +36,26 @@ export const bonusesByLocation = defineField({ description: "Bonus data reflecting the bonus given to employees for a given year.", type: "array", + options: { + sortable: false, + }, + components: { + input: (props: ArrayOfObjectsInputProps) => + ValueOrderedArrayOfObjectsInput({ + ...props, + valueCompareFn: (a, b) => { + if (isBonusPage(a)) { + if (isBonusPage(b)) { + return b.year - a.year; + } + return -1; + } else if (isBonusPage(b)) { + return 1; + } + return 0; + }, + }), + }, of: [ { type: "object", diff --git a/studio/schemas/objects/compensations/salariesByLocation.ts b/studio/schemas/objects/compensations/salariesByLocation.ts index 47510a633..4a56eafd6 100644 --- a/studio/schemas/objects/compensations/salariesByLocation.ts +++ b/studio/schemas/objects/compensations/salariesByLocation.ts @@ -1,7 +1,11 @@ -import { defineField } from "sanity"; +import { ArrayOfObjectsInputProps, defineField } from "sanity"; import { SalariesInput } from "studio/components/salariesInput/SalariesInput"; -import { SalariesPage } from "studio/lib/interfaces/compensations"; +import ValueOrderedArrayOfObjectsInput from "studio/components/ValueOrderedArrayOfObjectsInput"; +import { + SalariesPage, + isSalariesPage, +} from "studio/lib/interfaces/compensations"; import { companyLocationNameID } from "studio/schemas/documents/admin/companyLocation"; import { location, locationID } from "studio/schemas/objects/locations"; @@ -34,6 +38,26 @@ export const salariesByLocation = defineField({ description: "Salary data reflecting salaries given to employees for a given year. ", type: "array", + options: { + sortable: false, + }, + components: { + input: (props: ArrayOfObjectsInputProps) => + ValueOrderedArrayOfObjectsInput({ + ...props, + valueCompareFn: (a, b) => { + if (isSalariesPage(a)) { + if (isSalariesPage(b)) { + return b.year - a.year; + } + return -1; + } else if (isSalariesPage(b)) { + return 1; + } + return 0; + }, + }), + }, of: [ { type: "object",