diff --git a/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/ReviewContentPolicyStep.tsx b/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/ReviewContentPolicyStep.tsx index 1139e0c2f..8db8928db 100644 --- a/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/ReviewContentPolicyStep.tsx +++ b/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/ReviewContentPolicyStep.tsx @@ -5,6 +5,7 @@ import { isTPCollection } from 'modules/collection/utils' import { emailRegex } from 'lib/validators' import { Props } from './ReviewContentPolicyStep.types' import styles from './ReviewContentPolicyStep.module.css' +import { REVIEW_CONTENT_POLICY_CONTINUE_DATA_TEST_ID } from './constants' const termsOfUseLink = (link: string) => ( @@ -134,7 +135,7 @@ export const ReviewContentPolicyStep: React.FC = props => { - diff --git a/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/constants.ts b/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/constants.ts new file mode 100644 index 000000000..8d73b3ff9 --- /dev/null +++ b/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/constants.ts @@ -0,0 +1 @@ +export const REVIEW_CONTENT_POLICY_CONTINUE_DATA_TEST_ID = 'review-content-policy-continue-data-test-id' diff --git a/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/index.ts b/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/index.ts new file mode 100644 index 000000000..d5079cd29 --- /dev/null +++ b/src/components/Modals/PublishWizardCollectionModal/ReviewContentPolicyStep/index.ts @@ -0,0 +1,2 @@ +export * from './ReviewContentPolicyStep' +export * from './ReviewContentPolicyStep.types' diff --git a/src/components/Modals/PushChangesModal/PushChangesModal.container.tsx b/src/components/Modals/PushChangesModal/PushChangesModal.container.tsx new file mode 100644 index 000000000..16b552ec3 --- /dev/null +++ b/src/components/Modals/PushChangesModal/PushChangesModal.container.tsx @@ -0,0 +1,55 @@ +import { useCallback } from 'react' +import { AuthorizationStepStatus } from 'decentraland-ui' +import { shallowEqual, useDispatch, useSelector } from 'react-redux' +import { isLoadingType } from 'decentraland-dapps/dist/modules/loading/selectors' +import { getCollection, getError as getCollectionError, getLoading as getCollectionLoading } from 'modules/collection/selectors' +import { getCollectionThirdParty, getError as getThirdPartyError, getThirdPartyPublishStatus } from 'modules/thirdParty/selectors' +import { PUSH_COLLECTION_CURATION_REQUEST, pushCollectionCurationRequest } from 'modules/curations/collectionCuration/actions' +import { isThirdPartyCollection } from 'modules/collection/utils' +import { RootState } from 'modules/common/types' +import { publishAndPushChangesThirdPartyItemsRequest } from 'modules/thirdParty/actions' +import { OwnProps } from './PushChangesModal.types' +import { PushChangesModal } from './PushChangesModal' + +export default (props: OwnProps) => { + const dispatch = useDispatch() + const isPushingStandardCollectionChanges = useSelector((store: RootState) => + isLoadingType(getCollectionLoading(store), PUSH_COLLECTION_CURATION_REQUEST) + ) + const thirdPartyPublishStatus = useSelector((store: RootState) => getThirdPartyPublishStatus(store), shallowEqual) + const isPushingThirdPartyItemsChanges = + thirdPartyPublishStatus === AuthorizationStepStatus.WAITING || thirdPartyPublishStatus === AuthorizationStepStatus.PROCESSING + + const collection = useSelector((state: RootState) => getCollection(state, props.metadata.collectionId), shallowEqual) + const thirdPartyError = useSelector((state: RootState) => getThirdPartyError(state), shallowEqual) + const collectionError = useSelector((state: RootState) => getCollectionError(state), shallowEqual) + const error = thirdPartyError || collectionError + if (!collection) { + throw new Error('Collection not found') + } + + const isThirdParty = isThirdPartyCollection(collection) + const thirdParty = isThirdParty ? useSelector((store: RootState) => getCollectionThirdParty(store, collection)) : null + const isLoading = isPushingStandardCollectionChanges || isPushingThirdPartyItemsChanges + const onPushChanges = useCallback( + (email: string, subscribeToNewsletter: boolean) => { + if (thirdParty) { + dispatch( + publishAndPushChangesThirdPartyItemsRequest( + thirdParty, + [], + props.metadata.itemsWithChanges, + undefined, + email, + subscribeToNewsletter + ) + ) + } else { + dispatch(pushCollectionCurationRequest(props.metadata.collectionId)) + } + }, + [dispatch, props.metadata.collectionId, thirdParty, props.metadata.itemsWithChanges] + ) + + return +} diff --git a/src/components/Modals/PushChangesModal/PushChangesModal.module.css b/src/components/Modals/PushChangesModal/PushChangesModal.module.css new file mode 100644 index 000000000..7ce25b3f7 --- /dev/null +++ b/src/components/Modals/PushChangesModal/PushChangesModal.module.css @@ -0,0 +1,22 @@ +.content { + background-color: #1d1a20; + border-radius: 8px; + padding: 24px 27px 88px 27px; + font-size: 16px; + color: #cfcdd4; +} + +.actions { + margin-top: 24px; + width: 100%; + display: flex; + justify-content: space-between !important; +} + +.actions :global(.button) { + width: 180px; +} + +.error { + margin: 24px !important; +} diff --git a/src/components/Modals/PushChangesModal/PushChangesModal.spec.tsx b/src/components/Modals/PushChangesModal/PushChangesModal.spec.tsx new file mode 100644 index 000000000..b3b3efcea --- /dev/null +++ b/src/components/Modals/PushChangesModal/PushChangesModal.spec.tsx @@ -0,0 +1,77 @@ +import userEvent from '@testing-library/user-event' +import { Collection } from 'modules/collection/types' +import { renderWithProviders } from 'specs/utils' +import { Props } from './PushChangesModal.types' +import { PushChangesModal } from './PushChangesModal' +import { + PUSH_CHANGES_MODAL_CANCEL_CHANGES_DATA_TEST_ID, + PUSH_CHANGES_MODAL_CONFIRM_CHANGES_DATA_TEST_ID, + PUSH_CHANGES_MODAL_FIRST_STEP_DATA_TEST_ID +} from './constants' +import { REVIEW_CONTENT_POLICY_CONTINUE_DATA_TEST_ID } from '../PublishWizardCollectionModal/ReviewContentPolicyStep/constants' + +const renderPushChangesModal = (props: Partial = {}) => + renderWithProviders( + + ) + +let props: Partial +let renderedComponent: ReturnType + +beforeEach(() => { + props = {} +}) + +describe('when rendering the component', () => { + beforeEach(() => { + renderedComponent = renderPushChangesModal(props) + }) + + it('should start the modal in the first step', () => { + expect(renderedComponent.getByTestId(PUSH_CHANGES_MODAL_FIRST_STEP_DATA_TEST_ID)).toBeInTheDocument() + }) +}) + +describe('when rendering the component with an error', () => { + beforeEach(() => { + props.error = 'anError' + renderedComponent = renderPushChangesModal(props) + }) + + it('should render the error message', () => { + expect(renderedComponent.getByText('anError')).toBeInTheDocument() + }) +}) + +describe('when clicking cancel on the first step', () => { + beforeEach(() => { + props.onClose = jest.fn() + renderedComponent = renderPushChangesModal(props) + userEvent.click(renderedComponent.getByTestId(PUSH_CHANGES_MODAL_CANCEL_CHANGES_DATA_TEST_ID)) + }) + + it('should call onClose', () => { + expect(props.onClose).toHaveBeenCalled() + }) +}) + +describe('when clicking confirm on the first step', () => { + beforeEach(() => { + props.onPushChanges = jest.fn() + renderedComponent = renderPushChangesModal(props) + userEvent.click(renderedComponent.getByTestId(PUSH_CHANGES_MODAL_CONFIRM_CHANGES_DATA_TEST_ID)) + }) + + it('should switch to the ToS step', () => { + expect(renderedComponent.getByTestId(REVIEW_CONTENT_POLICY_CONTINUE_DATA_TEST_ID)).toBeInTheDocument() + }) +}) diff --git a/src/components/Modals/PushChangesModal/PushChangesModal.tsx b/src/components/Modals/PushChangesModal/PushChangesModal.tsx new file mode 100644 index 000000000..004bdd91c --- /dev/null +++ b/src/components/Modals/PushChangesModal/PushChangesModal.tsx @@ -0,0 +1,93 @@ +import { useCallback, useMemo, useState } from 'react' +import { Button, Message, ModalNavigation } from 'decentraland-ui' +import Modal from 'decentraland-dapps/dist/containers/Modal' +import { T, t } from 'decentraland-dapps/dist/modules/translation/utils' +import { ReviewContentPolicyStep } from '../PublishWizardCollectionModal/ReviewContentPolicyStep' +import styles from './PushChangesModal.module.css' +import { Props } from './PushChangesModal.types' +import { + PUSH_CHANGES_MODAL_CANCEL_CHANGES_DATA_TEST_ID, + PUSH_CHANGES_MODAL_CONFIRM_CHANGES_DATA_TEST_ID, + PUSH_CHANGES_MODAL_FIRST_STEP_DATA_TEST_ID +} from './constants' + +enum Steps { + CONFIRM_CHANGES = 'CONFIRM_CHANGES', + ACCEPT_TERMS = 'ACCEPT_TERMS' +} + +export const PushChangesModal = (props: Props) => { + const { onClose, onPushChanges, isLoading, error, collection } = props + + const [currentStep, setCurrentStep] = useState(Steps.CONFIRM_CHANGES) + const [email, setEmail] = useState('') + const [subscribeToNewsletter, setSubscribeToNewsletter] = useState(false) + + const stepTitle = useMemo(() => { + switch (currentStep) { + case Steps.CONFIRM_CHANGES: + return t('push_changes_modal.title') + case Steps.ACCEPT_TERMS: + return t('publish_wizard_collection_modal.title_review_content_policy') + } + }, [currentStep]) + + const handleProceedFromConfirmChanges = useCallback(() => { + setCurrentStep(Steps.ACCEPT_TERMS) + }, []) + + const handleGoBack = useCallback(() => { + setCurrentStep(Steps.CONFIRM_CHANGES) + }, []) + + const handleOnPushChanges = useCallback(() => { + onPushChanges(email, subscribeToNewsletter) + }, [onPushChanges, email, subscribeToNewsletter]) + + return ( + + + {currentStep === Steps.CONFIRM_CHANGES ? ( + +
+ +
+
+ + ) + }} + /> +
+ +
+ + +
+
+ ) : ( + + )} + {error ? ( + + {error} + + ) : null} +
+ ) +} diff --git a/src/components/Modals/PushChangesModal/PushChangesModal.types.ts b/src/components/Modals/PushChangesModal/PushChangesModal.types.ts new file mode 100644 index 000000000..9a415642b --- /dev/null +++ b/src/components/Modals/PushChangesModal/PushChangesModal.types.ts @@ -0,0 +1,17 @@ +import { ModalProps } from 'decentraland-dapps/dist/providers/ModalProvider/ModalProvider.types' +import { Collection } from 'modules/collection/types' +import { Item } from 'modules/item/types' + +type ModalMetadata = { + collectionId: string + itemsWithChanges: Item[] +} + +export type Props = OwnProps & { + onPushChanges: (email: string, subscribeToNewsletter: boolean) => unknown + isLoading: boolean + error: string | null + collection: Collection +} + +export type OwnProps = Omit & { metadata: ModalMetadata } diff --git a/src/components/Modals/PushChangesModal/constants.ts b/src/components/Modals/PushChangesModal/constants.ts new file mode 100644 index 000000000..37fa2ffc1 --- /dev/null +++ b/src/components/Modals/PushChangesModal/constants.ts @@ -0,0 +1,3 @@ +export const PUSH_CHANGES_MODAL_FIRST_STEP_DATA_TEST_ID = 'push-changes-modal-first-step-data-test-id' +export const PUSH_CHANGES_MODAL_CONFIRM_CHANGES_DATA_TEST_ID = 'push-changes-modal-confirm-changes-data-test-id' +export const PUSH_CHANGES_MODAL_CANCEL_CHANGES_DATA_TEST_ID = 'push-changes-modal-cancel-changes-data-test-id' diff --git a/src/components/Modals/PushChangesModal/index.ts b/src/components/Modals/PushChangesModal/index.ts new file mode 100644 index 000000000..69f4e6c71 --- /dev/null +++ b/src/components/Modals/PushChangesModal/index.ts @@ -0,0 +1,2 @@ +import PushChangesModal from './PushChangesModal.container' +export { PushChangesModal } diff --git a/src/components/Modals/index.ts b/src/components/Modals/index.ts index a01d47ebf..9ca4466b0 100644 --- a/src/components/Modals/index.ts +++ b/src/components/Modals/index.ts @@ -52,3 +52,4 @@ export { default as EnsMapAddressModal } from './ENSMapAddressModal' export { default as ReclaimNameModal } from './ReclaimNameModal' export { default as WorldPermissionsModal } from './WorldPermissionsModal' export { CreateCollectionSelectorModal } from './CreateCollectionSelectorModal' +export { PushChangesModal } from './PushChangesModal' diff --git a/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.container.ts b/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.container.ts index 516cd85c7..27ef2566e 100644 --- a/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.container.ts +++ b/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.container.ts @@ -26,6 +26,8 @@ const mapState = (state: RootState, ownProps: OwnProps): MapStateProps => { const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({ onNewClick: (collectionId: string, itemsWithChanges: Item[], itemsToPublish: Item[]) => dispatch(openModal('PublishWizardCollectionModal', { collectionId, itemsWithChanges, itemsToPublish })), + onPushChangesClick: (collectionId: string, itemsWithChanges: Item[]) => + dispatch(openModal('PushChangesModal', { collectionId, itemsWithChanges })), onClick: (collectionId: string, itemIds: string[], action: PublishButtonAction) => dispatch(openModal('PublishThirdPartyCollectionModal', { collectionId, itemIds, action })) }) diff --git a/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.tsx b/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.tsx index f7c4aaf5f..74f0b130e 100644 --- a/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.tsx +++ b/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.tsx @@ -27,6 +27,7 @@ const CollectionPublishButton = (props: Props) => { isLinkedWearablesPaymentsEnabled, onClick, onNewClick, + onPushChangesClick, itemsStatus, itemCurations, isLoadingItemCurations @@ -73,11 +74,23 @@ const CollectionPublishButton = (props: Props) => { const itemsToPushChanges = getItemsWithChanges(items, itemsStatus, itemCurations) if (isLinkedWearablesPaymentsEnabled && itemsToPublish.length > 0) { onNewClick(collection.id, itemsToPushChanges, itemsToPublish) + } else if (isLinkedWearablesPaymentsEnabled && itemsToPushChanges.length > 0) { + onPushChangesClick(collection.id, itemsToPushChanges) } else { const itemIds = items.map(item => item.id) onClick(collection.id, itemIds, buttonAction) } - }, [collection, items, buttonAction, onClick, onNewClick, isLinkedWearablesPaymentsEnabled, itemsStatus, itemCurations]) + }, [ + collection, + items, + buttonAction, + onClick, + onNewClick, + onPushChangesClick, + isLinkedWearablesPaymentsEnabled, + itemsStatus, + itemCurations + ]) const itemsTryingToPublish = useMemo( () => items.filter(item => !itemCurations?.find(itemCuration => itemCuration.itemId === item.id)).length, diff --git a/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.types.ts b/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.types.ts index 038031325..83fa7c70a 100644 --- a/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.types.ts +++ b/src/components/ThirdPartyCollectionDetailPage/CollectionPublishButton/CollectionPublishButton.types.ts @@ -20,10 +20,11 @@ export type Props = { itemsStatus: Record slots: number onClick: (collectionId: string, itemIds: string[], action: PublishButtonAction) => void + onPushChangesClick: (collectionId: string, itemsWithChanges: Item[]) => unknown onNewClick: (collectionId: string, itemsWithChanges: Item[], itemsToPublish: Item[]) => void } export type OwnProps = Pick export type MapStateProps = Pick -export type MapDispatchProps = Pick +export type MapDispatchProps = Pick export type MapDispatch = Dispatch diff --git a/src/modules/thirdParty/actions.ts b/src/modules/thirdParty/actions.ts index 175a1b393..13161e43d 100644 --- a/src/modules/thirdParty/actions.ts +++ b/src/modules/thirdParty/actions.ts @@ -183,9 +183,8 @@ export const FINISH_PUBLISH_AND_PUSH_CHANGES_THIRD_PARTY_ITEMS_FAILURE = '[Failu export const finishPublishAndPushChangesThirdPartyItemsSuccess = ( thirdParty: ThirdParty, collectionId: Collection['id'], - items: Item[], itemCurations: ItemCuration[] -) => action(FINISH_PUBLISH_AND_PUSH_CHANGES_THIRD_PARTY_ITEMS_SUCCESS, { thirdParty, collectionId, items, itemCurations }) +) => action(FINISH_PUBLISH_AND_PUSH_CHANGES_THIRD_PARTY_ITEMS_SUCCESS, { thirdParty, collectionId, itemCurations }) export const finishPublishAndPushChangesThirdPartyItemsFailure = (error: string) => action(FINISH_PUBLISH_AND_PUSH_CHANGES_THIRD_PARTY_ITEMS_FAILURE, { error }) diff --git a/src/modules/thirdParty/sagas.spec.ts b/src/modules/thirdParty/sagas.spec.ts index d356a5f98..c5aaa4b51 100644 --- a/src/modules/thirdParty/sagas.spec.ts +++ b/src/modules/thirdParty/sagas.spec.ts @@ -949,17 +949,47 @@ describe('when publishing & pushing changes to third party items', () => { ] ]) .put(updateThirdPartyActionProgress(100, ThirdPartyAction.PUSH_CHANGES)) // resets the progress - .put( - finishPublishAndPushChangesThirdPartyItemsSuccess(thirdParty, item.collectionId!, publishResponse, [ - ...itemCurations, - updatedItemCurations[0] - ]) - ) + .put(finishPublishAndPushChangesThirdPartyItemsSuccess(thirdParty, item.collectionId!, [...itemCurations, updatedItemCurations[0]])) .put(fetchThirdPartyAvailableSlotsRequest(thirdParty.id)) .dispatch(publishAndPushChangesThirdPartyItemsRequest(thirdParty, itemsToPublish, [itemWithChanges])) .run({ silenceTimeout: true }) }) }) + + describe("when there's only push changes to do", () => { + let updatedItemCurations: ItemCuration[] + beforeEach(() => { + updatedItemCurations = [ + { + id: 'id', + itemId: mockedItem.id, + createdAt: 0, + status: CurationStatus.PENDING, + updatedAt: 0, + contentHash: 'aHash' + } + ] + ;(mockBuilder.pushItemCuration as jest.Mock).mockResolvedValue(updatedItemCurations[0]) + collection.isPublished = true + linkedWearablesPaymentsEnabled = true + }) + + it('should put the finish publish & push changes success action and close the modal', () => { + return expectSaga(thirdPartySaga, mockBuilder, mockCatalystClient) + .provide([ + [call(getPublishItemsSignature, thirdParty.id, qty), { signature, salt, qty }], + [select(getItemCurations, item.collectionId), itemCurations], + [select(getCollection, item.collectionId), collection], + [select(getIsLinkedWearablesPaymentsEnabled), linkedWearablesPaymentsEnabled], + [take(FETCH_COLLECTION_SUCCESS), undefined] + ]) + .put(updateThirdPartyActionProgress(100, ThirdPartyAction.PUSH_CHANGES)) // resets the progress + .put(finishPublishAndPushChangesThirdPartyItemsSuccess(thirdParty, itemWithChanges.collectionId!, [updatedItemCurations[0]])) + .put(closeModal('PushChangesModal')) + .dispatch(publishAndPushChangesThirdPartyItemsSuccess(thirdParty, collection, [], [itemWithChanges])) + .run({ silenceTimeout: true }) + }) + }) }) describe('when handling the batched deployment of third party items', () => { @@ -1189,6 +1219,19 @@ describe('when handling the closing a modal', () => { }) }) + describe('and the modal is the push changes modal', () => { + beforeEach(() => { + modalName = 'PushChangesModal' + }) + + it('should clear the third party errors', () => { + return expectSaga(thirdPartySaga, mockBuilder, mockCatalystClient) + .dispatch(closeModal(modalName)) + .put(clearThirdPartyErrors()) + .run({ silenceTimeout: true }) + }) + }) + describe('and the modal is not the publish collection wizard', () => { beforeEach(() => { modalName = 'AnotherModalName' diff --git a/src/modules/thirdParty/sagas.ts b/src/modules/thirdParty/sagas.ts index 16e5efd3c..be57022ca 100644 --- a/src/modules/thirdParty/sagas.ts +++ b/src/modules/thirdParty/sagas.ts @@ -133,7 +133,7 @@ export function* thirdPartySaga(builder: BuilderAPI, catalystClient: CatalystCli yield takeEvery(CLOSE_MODAL, handleCloseModal) function* handleCloseModal(action: CloseModalAction) { - if (action.payload.name === 'PublishWizardCollectionModal') { + if (action.payload.name === 'PublishWizardCollectionModal' || action.payload.name === 'PushChangesModal') { yield put(clearThirdPartyErrors()) } } @@ -303,7 +303,7 @@ export function* thirdPartySaga(builder: BuilderAPI, catalystClient: CatalystCli function* handlePublishAndPushChangesThirdPartyItemRequest(action: PublishAndPushChangesThirdPartyItemsRequestAction) { const { thirdParty, maxSlotPrice, itemsToPublish, itemsWithChanges, email, subscribeToNewsletter, cheque } = action.payload - const collectionId = getCollectionId(itemsToPublish) + const collectionId = itemsToPublish.length > 0 ? getCollectionId(itemsToPublish) : getCollectionId(itemsWithChanges) const collection: ReturnType = yield select(getCollection, collectionId) const isLinkedWearablesPaymentsEnabled = (yield select(getIsLinkedWearablesPaymentsEnabled)) as ReturnType< typeof getIsLinkedWearablesPaymentsEnabled @@ -439,8 +439,16 @@ export function* thirdPartySaga(builder: BuilderAPI, catalystClient: CatalystCli yield put(closeModal('PublishWizardCollectionModal')) } - yield put(finishPublishAndPushChangesThirdPartyItemsSuccess(thirdParty, collection.id, resultFromPublish.newItems, newItemCurations)) - yield put(fetchThirdPartyAvailableSlotsRequest(thirdParty.id)) // re-fetch available slots after publishing + // If we're only pushing changes, close the push changes modal + if (isLinkedWearablesPaymentsEnabled && itemsToPublish.length === 0 && itemsWithChanges.length > 0) { + yield put(closeModal('PushChangesModal')) + } + + // Only fetch the third party slots if we're publishing new items + if (itemsToPublish.length > 0) { + yield put(fetchThirdPartyAvailableSlotsRequest(thirdParty.id)) // re-fetch available slots after publishing + } + yield put(finishPublishAndPushChangesThirdPartyItemsSuccess(thirdParty, collection.id, newItemCurations)) } catch (error) { yield put(finishPublishAndPushChangesThirdPartyItemsFailure(isErrorWithMessage(error) ? error.message : 'Unknown error')) if (!isLinkedWearablesPaymentsEnabled) { diff --git a/src/modules/translation/languages/en.json b/src/modules/translation/languages/en.json index 33d7c092e..7bbef8834 100644 --- a/src/modules/translation/languages/en.json +++ b/src/modules/translation/languages/en.json @@ -2380,5 +2380,9 @@ "unsynced": "Ready to push changes", "pending_migration": "Pending Migration", "pending_mapping": "Pending Mapping" + }, + "push_changes_modal": { + "title": "Push Changes", + "description": "Changes have been made to the collection or the items contained by it since the last time a curator has reviewed them.{br}In order to have this changes reflected in world, they have to be reviewed and approved again by the committee.{br}Are you sure you want to push the changes for review?" } } diff --git a/src/modules/translation/languages/es.json b/src/modules/translation/languages/es.json index 5881183be..febd2cad9 100644 --- a/src/modules/translation/languages/es.json +++ b/src/modules/translation/languages/es.json @@ -2398,5 +2398,9 @@ "unsynced": "Listo para enviar cambios", "pending_migration": "Migración pendiente", "pending_mapping": "Mapeo pendiente" + }, + "push_changes_modal": { + "title": "Enviar Cambios", + "description": "Se han realizado cambios en la colección o en los elementos que contiene desde la última vez que un curador los revisó.{br}Para que estos cambios se reflejen en el mundo, el comité debe revisarlos y aprobarlos nuevamente.{br}¿Está seguro de que desea enviar los cambios para su revisión?" } } diff --git a/src/modules/translation/languages/zh.json b/src/modules/translation/languages/zh.json index 7c3708194..728cd71f6 100644 --- a/src/modules/translation/languages/zh.json +++ b/src/modules/translation/languages/zh.json @@ -2379,5 +2379,9 @@ "unsynced": "已准备好发送更改", "pending_migration": "待迁移", "pending_mapping": "待定映射" + }, + "push_changes_modal": { + "title": "推送变更", + "description": "自上次策展人审核以来,馆藏或其包含的物品已发生更改。{br}为了使这些更改反映在世界上,委员会必须再次审核和批准这些更改。{br }您确定要推送更改以供审核吗?" } }