- Resolved persistent 'SyntaxError: Unexpected token class' by refactoring 'MediaState' and 'UI' classes in MediaManager.html to standard ES5 function constructors. - Resolved 'SyntaxError: Unexpected identifier src' by rewriting 'createCard' to use 'document.createElement' instead of template strings for dynamic media elements. - Consolidated script tags in MediaManager.html to prevent Apps Script parser merge issues. - Updated docs/ARCHITECTURE.md and MEMORY.md to formally document client-side constraints (No ES6 classes, strict DOM manipulation for media). - Note: Google Drive video animate-on-hover functionality is implemented but currently pending verification/fix.
159 lines
4.9 KiB
TypeScript
159 lines
4.9 KiB
TypeScript
import { IShopifyMediaService } from "../interfaces/IShopifyMediaService"
|
|
import { IShop } from "../interfaces/IShop"
|
|
import { formatGqlForJSON, buildGqlQuery } from "../shopifyApi"
|
|
|
|
export class ShopifyMediaService implements IShopifyMediaService {
|
|
private shop: IShop
|
|
|
|
constructor(shop: IShop) {
|
|
this.shop = shop
|
|
}
|
|
|
|
stagedUploadsCreate(input: any[]): any {
|
|
const query = /* GraphQL */ `
|
|
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
|
|
stagedUploadsCreate(input: $input) {
|
|
stagedTargets {
|
|
url
|
|
resourceUrl
|
|
parameters {
|
|
name
|
|
value
|
|
}
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`
|
|
const variables = { input }
|
|
const payload = buildGqlQuery(query, variables)
|
|
const response = this.shop.shopifyGraphQLAPI(payload)
|
|
return response.content.data.stagedUploadsCreate
|
|
}
|
|
|
|
productCreateMedia(productId: string, media: any[]): any {
|
|
const query = /* GraphQL */ `
|
|
mutation productCreateMedia($media: [CreateMediaInput!]!, $productId: ID!) {
|
|
productCreateMedia(media: $media, productId: $productId) {
|
|
media {
|
|
id
|
|
alt
|
|
mediaContentType
|
|
status
|
|
}
|
|
mediaUserErrors {
|
|
field
|
|
message
|
|
}
|
|
product {
|
|
id
|
|
title
|
|
}
|
|
}
|
|
}
|
|
`
|
|
const variables = {
|
|
productId,
|
|
media
|
|
}
|
|
const payload = buildGqlQuery(query, variables)
|
|
const response = this.shop.shopifyGraphQLAPI(payload)
|
|
return response.content.data.productCreateMedia
|
|
}
|
|
getProductMedia(productId: string): any[] {
|
|
const query = /* GraphQL */ `
|
|
query getProductMedia($productId: ID!) {
|
|
product(id: $productId) {
|
|
media(first: 250) {
|
|
edges {
|
|
node {
|
|
id
|
|
alt
|
|
mediaContentType
|
|
preview {
|
|
image {
|
|
originalSrc
|
|
}
|
|
}
|
|
... on Video {
|
|
sources {
|
|
url
|
|
mimeType
|
|
}
|
|
}
|
|
... on MediaImage {
|
|
image {
|
|
url
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`
|
|
const variables = { productId }
|
|
const payload = buildGqlQuery(query, variables)
|
|
const response = this.shop.shopifyGraphQLAPI(payload)
|
|
if (!response || !response.content || !response.content.data || !response.content.data.product) {
|
|
console.error("getProductMedia: Invalid response or product not found. Raw Response:", JSON.stringify(response));
|
|
throw new Error(`Product not found or access denied for ID: ${productId}. See Logs for details.`);
|
|
}
|
|
return response.content.data.product.media.edges.map((edge: any) => edge.node)
|
|
}
|
|
|
|
productDeleteMedia(productId: string, mediaId: string): any {
|
|
const query = /* GraphQL */ `
|
|
mutation productDeleteMedia($mediaIds: [ID!]!, $productId: ID!) {
|
|
productDeleteMedia(mediaIds: $mediaIds, productId: $productId) {
|
|
deletedMediaIds
|
|
mediaUserErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`
|
|
const variables = { productId, mediaIds: [mediaId] }
|
|
const payload = buildGqlQuery(query, variables)
|
|
const response = this.shop.shopifyGraphQLAPI(payload)
|
|
if (!response || !response.content || !response.content.data) {
|
|
console.error("productDeleteMedia failed. Response:", JSON.stringify(response))
|
|
if (response && response.content && response.content.errors) {
|
|
console.error("GraphQL Errors:", JSON.stringify(response.content.errors))
|
|
}
|
|
throw new Error(`Shopify API failed for productDeleteMedia: ${response ? 'Invalid Response' : 'No Response'}`)
|
|
}
|
|
return response.content.data.productDeleteMedia
|
|
}
|
|
|
|
productReorderMedia(productId: string, moves: any[]): any {
|
|
const query = /* GraphQL */ `
|
|
mutation productReorderMedia($id: ID!, $moves: [MoveInput!]!) {
|
|
productReorderMedia(id: $id, moves: $moves) {
|
|
job {
|
|
id
|
|
done
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`
|
|
const variables = { id: productId, moves }
|
|
const payload = buildGqlQuery(query, variables)
|
|
const response = this.shop.shopifyGraphQLAPI(payload)
|
|
return response.content.data.productReorderMedia
|
|
return response.content.data.productReorderMedia
|
|
}
|
|
|
|
getShopDomain(): string {
|
|
return this.shop.getShopDomain()
|
|
}
|
|
}
|