-
Notifications
You must be signed in to change notification settings - Fork 4
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
cleanup compensation and add the start of bonus #569
Changes from 9 commits
a113a7a
bd82336
0099991
fe57690
362c272
506c90a
f56a048
b9dc346
30433d1
a86a5e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { defineField } from "sanity"; | ||
|
||
export const companyLocationsID = "companyLocations"; | ||
export const companyLocationID = "companyLocation"; | ||
|
||
const companyLocations = defineField({ | ||
name: companyLocationsID, | ||
type: "document", | ||
title: "Location", | ||
description: "Content related to an individual location within the company", | ||
fields: [ | ||
defineField({ | ||
name: companyLocationID, | ||
type: "string", | ||
title: "Location", | ||
}), | ||
], | ||
}); | ||
|
||
export default companyLocations; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,9 @@ | ||
import { defineField, defineType } from "sanity"; | ||
import { titleSlug } from "../schemaTypes/slug"; | ||
import seo from "../objects/seo"; | ||
import locations from "../objects/locations"; | ||
import { title } from "../fields/text"; | ||
import { benefitId } from "./benefit"; | ||
|
||
// maximum number of locations to display in the preview without truncating | ||
const LOCATIONS_PREVIEW_CUTOFF = 3; | ||
import { bonusesByLocation } from "../objects/compensations/bonusesByLocation"; | ||
|
||
export const compensationsId = "compensations"; | ||
|
||
|
@@ -15,74 +12,59 @@ const compensations = defineType({ | |
type: "document", | ||
title: "Compensations", | ||
fields: [ | ||
locations, | ||
title, | ||
{ | ||
...title, | ||
title: "Compensation Page Title", | ||
description: | ||
"Enter the primary title that will be displayed at the top of the compensation page. This is what users will see when they visit the page.", | ||
}, | ||
titleSlug, | ||
seo, | ||
defineField({ | ||
name: "showSalaryCalculator", | ||
title: "Show Salary Calculator", | ||
description: "Should the salary calculator be visible on the page?", | ||
type: "boolean", | ||
initialValue: true, | ||
}), | ||
// add pension here. pension doesn't rely on locations | ||
bonusesByLocation, | ||
// add salary here | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to keep these comments so we know what's expected here once we add pension, benefits and salary |
||
// benefits should be updated to match the grouping by location: | ||
// defineField({ | ||
// name: "benefits", | ||
// title: "Benefits", | ||
// type: "array", | ||
// of: [ | ||
// defineField({ | ||
// name: "benefitGroup", | ||
// title: "Benefit Group", | ||
// type: "object", | ||
// fields: [ | ||
// locations, | ||
// defineField({ | ||
// name: "benefitsList", | ||
// title: "List of Benefits", | ||
// type: "array", | ||
// of: [{ type: benefitId }], | ||
// }), | ||
// ], | ||
// }), | ||
// ], | ||
// }), | ||
// IMPORTANT: this is just a very simple mockup and might not represent a good ux | ||
defineField({ | ||
christinaroise marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name: "benefits", | ||
title: "Benefits", | ||
description: "Manage benefits for the compensations page", | ||
title: "Included Benefits", | ||
description: | ||
"Add and manage information on the benefits included with the compensation package, such as health insurance, retirement plans, and paid time off.", | ||
type: "array", | ||
of: [{ type: benefitId }], | ||
}), | ||
seo, | ||
], | ||
preview: { | ||
select: { | ||
title: "basicTitle", | ||
/* | ||
Access array object values using dot notation with the array index, e.g., "locations.0.basicTitle". | ||
This approach allows selecting a subset of the array for preview purposes. | ||
For more details, see: https://www.sanity.io/docs/previews-list-views#62febb15a63a | ||
*/ | ||
...[...Array(LOCATIONS_PREVIEW_CUTOFF + 1).keys()].reduce( | ||
(o, i) => ({ ...o, [`location${i}`]: `locations.${i}.basicTitle` }), | ||
{}, | ||
), | ||
title: "title", | ||
}, | ||
prepare({ title, ...locationsMap }) { | ||
prepare({ title }) { | ||
return { | ||
title, | ||
subtitle: previewStringFromLocationsMap( | ||
locationsMap, | ||
LOCATIONS_PREVIEW_CUTOFF, | ||
), | ||
}; | ||
}, | ||
}, | ||
}); | ||
|
||
/** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we most likely want to copy paste this into benefits and salary but removing for now. |
||
* Generates a preview string based on the selected office locations. | ||
* | ||
* @param {Object} locationsMap - A map of office titles selected for preview, e.g., { office0: "Trondheim", office1: "Oslo", ... }. | ||
* @param {number} cutoff - The maximum number of locations to display before shortening the preview string. | ||
* @returns {string|undefined} - A formatted string summarizing the selected locations or `undefined` if no locations are selected. | ||
*/ | ||
function previewStringFromLocationsMap( | ||
locationsMap: { | ||
[key: string]: string; | ||
}, | ||
cutoff: number, | ||
): string | undefined { | ||
const locations = Object.values<string>(locationsMap).filter( | ||
(o) => o !== undefined, | ||
); | ||
if (locations.length === 0) { | ||
return undefined; | ||
} else if (locations.length === 1) { | ||
return `Location: ${locations[0]}`; | ||
} else if (locations.length > cutoff) { | ||
return `Locations: ${locations.toSpliced(cutoff - 1).join(", ")}, and more`; | ||
} | ||
return `Locations: ${locations.toSpliced(-1).join(", ")} and ${locations.at(-1)}`; | ||
} | ||
|
||
export default compensations; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { defineField } from "sanity"; | ||
import { location, locationID } from "../locations"; | ||
import { companyLocationID } from "studio/schemas/documents/companyLocations"; | ||
|
||
export const bonusesByLocation = defineField({ | ||
name: "bonusesByLocation", | ||
title: "Bonus by Location", | ||
description: | ||
"Enter the average bonus amount for each company location. Each location can have only one bonus entry, but you can assign the same bonus amount to multiple locations.", | ||
type: "array", | ||
of: [ | ||
defineField({ | ||
name: "bonusData", | ||
title: "Bonus Information", | ||
description: | ||
"Details of the bonus amount specific to a particular location. Each location should have a unique entry with the average bonus calculated for that site.", | ||
type: "object", | ||
fields: [ | ||
{ | ||
...location, | ||
description: | ||
"Select the company location for which you are entering the average bonus information. Each location must be unique.", | ||
validation: (Rule) => Rule.required(), | ||
}, | ||
defineField({ | ||
name: "averageBonus", | ||
title: "Average Bonus", | ||
description: | ||
"Enter the average bonus amount for this location. Ensure the amount is positive and reflective of the compensation package for this location.", | ||
type: "number", | ||
validation: (Rule) => | ||
Rule.required() | ||
.min(0) | ||
.error("Please enter a positive bonus amount."), | ||
}), | ||
], | ||
preview: { | ||
select: { | ||
averageBonus: "averageBonus", | ||
location: `${locationID}.${companyLocationID}`, | ||
}, | ||
prepare({ averageBonus, location }) { | ||
return { | ||
title: `Average Bonus: ${averageBonus || "N/A"}`, | ||
subtitle: `Location: ${location || "No location selected"}`, | ||
}; | ||
}, | ||
}, | ||
}), | ||
], | ||
validation: (Rule) => | ||
Rule.custom((bonusesByLocation, context) => { | ||
const duplicateCheck = checkForDuplicateLocations( | ||
bonusesByLocation as BonusEntry[] | undefined, | ||
); | ||
|
||
if (duplicateCheck !== true) return duplicateCheck; | ||
|
||
return true; | ||
christinaroise marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}), | ||
}); | ||
|
||
interface LocationReference { | ||
_ref: string; | ||
_type: string; | ||
title?: string; | ||
} | ||
|
||
interface BonusEntry { | ||
location: LocationReference; | ||
averageBonus: number; | ||
} | ||
|
||
/** | ||
* Checks for duplicate location references in the bonusesByLocation array. | ||
* Ensures each location has a unique bonus entry. | ||
* | ||
* @param {BonusEntry[] | undefined} bonusesByLocation - The array of bonus entries, each with one or more locations. | ||
* @returns {string | true} - Returns an error message if duplicate locations are found, or true if all are unique. | ||
*/ | ||
const checkForDuplicateLocations = ( | ||
bonusesByLocation: BonusEntry[] | undefined, | ||
): string | true => { | ||
if (!bonusesByLocation) return true; | ||
|
||
const locationRefs = bonusesByLocation | ||
.map((entry) => entry.location?._ref) | ||
.filter(Boolean); | ||
|
||
const uniqueRefs = new Set(locationRefs); | ||
|
||
if (uniqueRefs.size !== locationRefs.length) { | ||
return "Each location should be listed only once in the bonuses list. You can assign the same bonus amount to multiple locations, but make sure no location appears more than once."; | ||
} | ||
|
||
return true; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,26 @@ | ||
import { defineField } from "sanity"; | ||
import { locationId } from "../documents/location"; | ||
import { companyLocationsID } from "../documents/companyLocations"; | ||
|
||
const locations = defineField({ | ||
name: "locations", | ||
export const locationsID = "locations"; | ||
export const locationID = "location"; | ||
|
||
export const location = defineField({ | ||
name: locationID, | ||
type: "reference", | ||
title: "Select a location", | ||
description: | ||
"Select the office location this content applies to. If it applies to all locations, you can leave this field empty.", | ||
to: [{ type: companyLocationsID }], | ||
options: { | ||
disableNew: true, | ||
}, | ||
}); | ||
|
||
export const locations = defineField({ | ||
name: locationsID, | ||
type: "array", | ||
title: "Relevant Locations", | ||
description: | ||
"You can tailor this content to specific office locations by selecting them here. If the content applies to all locations, just leave this field empty.", | ||
of: [ | ||
{ | ||
title: "Select a location", | ||
type: "reference", | ||
to: [{ type: locationId }], | ||
options: { | ||
disableNew: true, | ||
}, | ||
}, | ||
], | ||
of: [location], | ||
}); | ||
|
||
export default locations; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for a better differentiation between i.e benefits.locations and companyLocations I renamed this part