sanity-io / sanity-plugin-internationalized-array

A plugin to register array fields with a custom input component to store field values in multiple languages, queryable by using the language ID as an array `_key`.
MIT License
45 stars 11 forks source link

Document usage with patches #85

Open leeuwd opened 3 weeks ago

leeuwd commented 3 weeks ago

Is your feature request related to a problem? Please describe.

I'm using the plugin with array setup.

The context is a Shopify Next.js headless setup, with a custom handler for the Sanity Connect Shopify app. It's a multi-instance Shopify setup, so the customer handler endpoint is called with by multiple Shopify instances their Sanity Connect app.

So far, so good:

image

I'm using a transaction to update the Sanity product document:

const productDocument = {
   _type: 'product',
  _id: `product-${product.handle}`,
  shopifyIsAvailable: [{ _key: locale, _type: 'internationalizedArrayBooleanValue', value: product.status === 'active' }],
} satisfies Partial<Product>

const transaction = client.transaction()

transaction
  .createIfNotExists(productDocument)
  .patch(productDocument._id, patchHandler)

Effectively shopifyIsAvailable is a({_key: string, value: string} | undefined)[].

I'm unsure how to update the array values of shopifyIsAvailable. The_key with the right locale might be there, or not.

Describe the solution you'd like

The client has an insert method. Ideally, I would like an upsert method as well, that updates if the locale exists, and inserts the locale does't exist.

For the time being, perhaps this plugin could document intended usage when using the client library to update the locale-specific values.

Describe alternatives you've considered

// does not work
 const patchHandler = (patch: Patch) => {
      return patch
        .setIfMissing({ shopifyIsAvailable: [] })
        .unset([`shopifyIsAvailable[_key==\"${locale}\"]`])
        .append(`shopifyIsAvailable[_key==\"${locale}\"]`, productDocument.shopifyIsAvailable)
}

// does not work
const patchHandler = (patch: Patch) => {
      return patch
        .setIfMissing({ shopifyIsAvailable: [] })
        .insert('replace', `shopifyIsAvailable[_key==\"${locale}\"]`, productDocument.shopifyIsAvailable)
}

Additional context

https://github.com/sanity-io/sanity-plugin-internationalized-array/issues/79 would also help since I can use an alternative 'Shopify []' instead of 'locales []'.

leeuwd commented 3 weeks ago

I think I've found a solution, but I feel this should/could be done more elegantly.


const createInternationalizedArray = <V, T extends string>(locale: LocaleIdentifier, value: V, type: T) => {
  return locales.map((l) => ({
    _key: l,
    _type: type,
    value: l === locale ? value : undefined,
  }))
}

const createPatchHandler = (locale: LocaleIdentifier, product: SanityConnectProduct, productDocument: Partial<Product>) => {
  return (patch: Patch) => {
    return patch
      .setIfMissing({
        title: productDocument.title,
        shopifyProductId: productDocument.shopifyProductId,
        shopifyIsAvailable: productDocument.shopifyIsAvailable,
      })
      .set({
        shopifySynchronizedAt: productDocument.shopifySynchronizedAt,
        [`title[_key=="${locale}"].value`]: product.title,
        [`shopifyProductId[_key=="${locale}"].value`]: product.id,
        [`shopifyIsAvailable[_key=="${locale}"].value`]: product.status === 'active',
      })
      .insert('replace', `title[_key=="${locale}"]`, [{ _key: locale, _type: 'internationalizedArrayStringValue', value: product.title }])
      .insert('replace', `shopifyProductId[_key=="${locale}"]`, [{ _key: locale, _type: 'internationalizedArrayStringValue', value: product.id }])
      .insert('replace', `shopifyIsAvailable[_key=="${locale}"]`, [{ _key: locale, _type: 'internationalizedArrayBooleanValue', value: product.status === 'active' }])
  }
}

const productDocument = {
  _type: 'product',
  _id: `product-${product.handle}`,
  shopifySynchronizedAt: new Date().toISOString(),
  shopifyIsAvailable: createInternationalizedArray(locale, product.status === 'active', 'internationalizedArrayBooleanValue'),
} satisfies Partial<Product>

const transaction = sanityAdminClient.transaction()
const patchHandler = createPatchHandler(locale, product, productDocument)

transaction.createIfNotExists(productDocument).patch(productDocument._id, patchHandler)
await transaction.commit({ visibility: 'deferred', dryRun: false })