* Add gift cards section to menu and add empty list component * Update messages * Change styling of app wide page header to match design * Add gift cards list table wip * Update prop name for status chip component to make it more consistent with other components * Replace old trash icon with new one * Add Size type based on action dialog sizes to be used app wide * Add delete icon button * Add new sizes option to status chip component * Add / update gift cards list components * Add bulk actions type * Work on gift cards list WIP * Small refactor * Fix styling of gift cards table * Remove temp files * Remove unnecessary type * Add gift cards section to menu and add empty list component * Update schema and types * Add link to gift card update page to gift cards list and add route to gift cards index * Extract order page title with status chip into a separate generic component and use it in order page title * wip * Update money component * Add gift card details card balance section * Refactor gift card details * Add vertical spacer component * Update schema and types * Add gift card tag input component along with necessary queries * Add gift card tag input to gift card update page * Add gift card update details card expiry section WIP * Add time period select field WIP * Post rebase refactor * Add time period select field to gift card update view * Fixes after review * Update schema, types and gift cards query * Add getFullName util function and replace existing manual usages * Add text with select field component * Add gift card update info card and refactor * Fix import * Add displaying order link in gift card update * Refactor * Connect gift card list to api * refactor * Add gift card create dialog * Fix gift card list styles, change location for gift card list query, minor refactor * Fix menu structure data for gift cards * Add channel currencies type to shop * Refactor text with select field * Add gift card expiry select component * Add gift card error type and fragment * Update global types * Add default prop to getFormErrors function * Move gift card details provider to providers dir * Update global utils with mapSingleValueNodeToChoice function * Update gift card tag input * Move and refactor time period field * Update schema * move format money function to other money ulities * Update gift card urls * Add content or skeleton component * Add gift card create util for extracting expiry settings input data * Remove content or skeleton component and move displaying logic to existing skeleton * Move displaying logic of gift card create dialog to list * Refactor * Add hooks for gift card bulk actions and gift card list to be used instead of context directly * Fix types for text with select field + add parsing for number typed field * Add initial currency to gift card create form * Fix gift card create dialog closing animation * Add gift card update info card * Refactor gift card update details card * Add gift card balance dialog * Move gift card update form providers to providers dir * Connect gift card update page to api, add necessary contexts etc. * Refactor * Refactor * Add hooks to use instead of gift card contexts directly * Fix types * Fix text field target name missing in passed event in text with select field * Add minimal value option to text with select field, add to gift card inputs * Fix gift card update balance dialog not changing hasChanged prop after submit * Refactor * Fix update balance dialog crashing the app when enetered wrong amount * Fix gift card list table header styles * Add enable / disable section to gift card update * Refactor * Refactor * Refactor * Add metadata to gift card update * Update messages ids * Refactor * Refactor * Refactor * Refactor * Update types after rebase * Fix types * Fixes after qa * Fix tests
This commit is contained in:
parent
6b24fa0dc3
commit
dae95cb410
142 changed files with 11118 additions and 670 deletions
|
@ -1459,6 +1459,9 @@
|
|||
"context": "dialog title",
|
||||
"string": "Delete categories"
|
||||
},
|
||||
"src_dot_channel": {
|
||||
"string": "Channel"
|
||||
},
|
||||
"src_dot_channels": {
|
||||
"context": "channels section name",
|
||||
"string": "Channels"
|
||||
|
@ -1681,8 +1684,8 @@
|
|||
"context": "tab name",
|
||||
"string": "All Collections"
|
||||
},
|
||||
"src_dot_collections_dot_components_dot_CollectionListPage_dot_4057224233": {
|
||||
"string": "Search Collection"
|
||||
"src_dot_collections_dot_components_dot_CollectionListPage_dot_2685595924": {
|
||||
"string": "Search Collections"
|
||||
},
|
||||
"src_dot_collections_dot_components_dot_CollectionListPage_dot_686910896": {
|
||||
"context": "button",
|
||||
|
@ -1709,6 +1712,18 @@
|
|||
"context": "collection availability",
|
||||
"string": "Availability"
|
||||
},
|
||||
"src_dot_collections_dot_components_dot_CollectionList_dot_published": {
|
||||
"context": "collection publication date",
|
||||
"string": "Published on {date}"
|
||||
},
|
||||
"src_dot_collections_dot_components_dot_CollectionList_dot_unpublished": {
|
||||
"context": "collection publication date",
|
||||
"string": "Unpublished"
|
||||
},
|
||||
"src_dot_collections_dot_components_dot_CollectionList_dot_willBePublished": {
|
||||
"context": "collection publication date",
|
||||
"string": "Becomes published on {date}"
|
||||
},
|
||||
"src_dot_collections_dot_components_dot_CollectionProducts_dot_1657559629": {
|
||||
"string": "No products found"
|
||||
},
|
||||
|
@ -3385,6 +3400,218 @@
|
|||
"src_dot_generalInformations": {
|
||||
"string": "General Information"
|
||||
},
|
||||
"src_dot_giftCards": {
|
||||
"context": "gift cards section name",
|
||||
"string": "Gift Cards"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_amountLabel": {
|
||||
"context": "GiftCardCreateDialog amount label",
|
||||
"string": "Enter amount"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_copiedToClipboardTitle": {
|
||||
"context": "GiftCardCreateDialog copied to clipboard title",
|
||||
"string": "Copied to clipboard"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_copyCodeLabel": {
|
||||
"context": "GiftCardCreateDialog copy code label",
|
||||
"string": "Copy code"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_createdGiftCardLabel": {
|
||||
"context": "GiftCardCreateDialog created gift card label",
|
||||
"string": "This is the code of a created gift card:"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_createdSuccessAlertTitle": {
|
||||
"context": "GiftCardCreateDialog createdSuccessAlertTitle",
|
||||
"string": "Successfully created gift card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_customerLabel": {
|
||||
"context": "GiftCardCreateDialog customer label",
|
||||
"string": "Customer"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_customerSubtitle": {
|
||||
"context": "GiftCardCreateDialog customer subtitle",
|
||||
"string": "Selected customer will be sent the generated gift card code. Someone else can redeem the gift card code. Gift card will be assigned to account which redeemed the code."
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_issueButtonLabel": {
|
||||
"context": "GiftCardCreateDialog issue button label",
|
||||
"string": "Issue"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_noteLabel": {
|
||||
"context": "GiftCardCreateDialog note label",
|
||||
"string": "Note"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_noteSubtitle": {
|
||||
"context": "GiftCardCreateDialog note subtitle",
|
||||
"string": "Why was this gift card issued. This note will not be shown to the customer. Note will be stored in gift card history"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardCreateDialog_dot_title": {
|
||||
"context": "GiftCardCreateDialog title",
|
||||
"string": "Issue gift card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateBalanceDialog_dot_changeButtonLabel": {
|
||||
"context": "GiftCardUpdateDetailsCard set balance dialog change button label",
|
||||
"string": "Change"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateBalanceDialog_dot_subtitle": {
|
||||
"context": "GiftCardUpdateDetailsCard set balance dialog subtitle",
|
||||
"string": "What would you like to set cards balance to. When you change the balance both values will be changed"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateBalanceDialog_dot_title": {
|
||||
"context": "GiftCardUpdateDetailsCard set balance button label",
|
||||
"string": "Set balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateBalanceDialog_dot_updatedSuccessAlertTitle": {
|
||||
"context": "GiftCardUpdateDetailsCard update success alert title",
|
||||
"string": "Successfully updated card balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateDetailsCard_dot_cardBalanceLabel": {
|
||||
"context": "GiftCardUpdateDetailsCard card balance label",
|
||||
"string": "Card Balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateDetailsCard_dot_setBalanceButtonLabel": {
|
||||
"context": "GiftCardUpdateDetailsCard set balance button label",
|
||||
"string": "set balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateDetailsCard_dot_title": {
|
||||
"context": "GiftCardUpdateDetailsCard title",
|
||||
"string": "Details"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_boughtByLabel": {
|
||||
"context": "GiftCardUpdateInfoCard bought by label",
|
||||
"string": "Bought by"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_creationLabel": {
|
||||
"context": "GiftCardUpdateInfoCard creation label",
|
||||
"string": "Creation"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_issuedByAppLabel": {
|
||||
"context": "GiftCardUpdateInfoCard issued by app label",
|
||||
"string": "Issued by app"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_issuedByLabel": {
|
||||
"context": "GiftCardUpdateInfoCard issued by label",
|
||||
"string": "Issued by"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_orderNumberLabel": {
|
||||
"context": "GiftCardUpdateInfoCard order number label",
|
||||
"string": "Order number"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_productLabel": {
|
||||
"context": "GiftCardUpdateInfoCard product label",
|
||||
"string": "Product bought to get gift card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_title": {
|
||||
"context": "GiftCardUpdateInfoCard title",
|
||||
"string": "Card information"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdateInfoCard_dot_usedByLabel": {
|
||||
"context": "GiftCardUpdateInfoCard used by label",
|
||||
"string": "Used by"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdatePageHeader_dot_disableLabel": {
|
||||
"context": "GiftCardEnableDisableSection enable label",
|
||||
"string": "Disable"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdatePageHeader_dot_enableLabel": {
|
||||
"context": "GiftCardEnableDisableSection enable label",
|
||||
"string": "Enable"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdatePageHeader_dot_successfullyDisabledTitle": {
|
||||
"context": "GiftCardEnableDisableSection disable success",
|
||||
"string": "Successfully disabled gift card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_GiftCardUpdatePageHeader_dot_successfullyEnabledTitle": {
|
||||
"context": "GiftCardEnableDisableSection enable success",
|
||||
"string": "Successfully enabled gift card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardUpdate_dot_title": {
|
||||
"context": "GiftCardUpdateDetailsCard title",
|
||||
"string": "Details"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_bulkIssue": {
|
||||
"context": "GiftCardsListHeader menu item settings",
|
||||
"string": "Bulk Issue"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_codeEndingWithLabel": {
|
||||
"context": "GiftCardsListTable code ending with label",
|
||||
"string": "Code ending with {displayCode}"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_exportCodes": {
|
||||
"context": "GiftCardsListHeader menu item settings",
|
||||
"string": "Export card codes"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_giftCardDisabledLabel": {
|
||||
"context": "GiftCardsListTable disabled label",
|
||||
"string": "Disabled"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_giftCardsTableColumnBalanceTitle": {
|
||||
"context": "GiftCardsListTable column title balance",
|
||||
"string": "Balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_giftCardsTableColumnCustomerTitle": {
|
||||
"context": "GiftCardsListTable column title customer",
|
||||
"string": "Used by"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_giftCardsTableColumnGiftCardTitle": {
|
||||
"context": "GiftCardsListTable column title gift card",
|
||||
"string": "Gift Card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_giftCardsTableColumnProductTitle": {
|
||||
"context": "GiftCardsListTable column title product",
|
||||
"string": "Product"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_giftCardsTableColumnTagTitle": {
|
||||
"context": "GiftCardsListTable column title tag",
|
||||
"string": "Tag"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_issueButtonLabel": {
|
||||
"context": "GiftCardsListHeader issue button label",
|
||||
"string": "Issue card"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_noGiftCardsFound": {
|
||||
"context": "GiftCardsListTable no cards found title",
|
||||
"string": "No gift cards found"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_settings": {
|
||||
"context": "GiftCardsListHeader menu item settings",
|
||||
"string": "Settings"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_GiftCardExpirySelect_dot_expirationDateLabel": {
|
||||
"context": "GiftCarUpdateDetailsExpirySection expiration date label",
|
||||
"string": "Expiration date"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_GiftCardExpirySelect_dot_expiryDateLabel": {
|
||||
"context": "GiftCarUpdateDetailsExpirySection expiry date label",
|
||||
"string": "Expiration date"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_GiftCardExpirySelect_dot_expiryPeriodLabel": {
|
||||
"context": "GiftCarUpdateDetailsExpirySection expiry period label",
|
||||
"string": "Expiry period"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_GiftCardExpirySelect_dot_neverExpireLabel": {
|
||||
"context": "GiftCarUpdateDetailsExpirySection never expire label",
|
||||
"string": "Never expire"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_GiftCardTagInput_dot_label": {
|
||||
"context": "GiftCardTagInput tag label",
|
||||
"string": "Card Tag"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_GiftCardTagInput_dot_placeholder": {
|
||||
"context": "GiftCardTagInput tag placeholder",
|
||||
"string": "Tag"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_TimePeriodField_dot_dayLabel": {
|
||||
"context": "TimePeriodTextWithSelectField day label",
|
||||
"string": "days after usage"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_TimePeriodField_dot_monthLabel": {
|
||||
"context": "TimePeriodTextWithSelectField month label",
|
||||
"string": "months after usage"
|
||||
},
|
||||
"src_dot_giftCards_dot_components_dot_TimePeriodField_dot_yearLabel": {
|
||||
"context": "TimePeriodTextWithSelectField year label",
|
||||
"string": "years after usage"
|
||||
},
|
||||
"src_dot_home": {
|
||||
"context": "home section name",
|
||||
"string": "Home"
|
||||
|
@ -5231,18 +5458,6 @@
|
|||
"context": "products section name",
|
||||
"string": "Products"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductAvailabilityStatusLabel_dot_published": {
|
||||
"context": "product publication date",
|
||||
"string": "Published on {date}"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductAvailabilityStatusLabel_dot_unpublished": {
|
||||
"context": "product publication date",
|
||||
"string": "Unpublished"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductAvailabilityStatusLabel_dot_willBePublished": {
|
||||
"context": "product publication date",
|
||||
"string": "Becomes published on {date}"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductCategoryAndCollectionsForm_dot_1755013298": {
|
||||
"string": "Category"
|
||||
},
|
||||
|
@ -5466,6 +5681,18 @@
|
|||
"context": "product",
|
||||
"string": "Name"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductList_dot_published": {
|
||||
"context": "product publication date",
|
||||
"string": "Published on {date}"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductList_dot_unpublished": {
|
||||
"context": "product publication date",
|
||||
"string": "Unpublished"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductList_dot_willBePublished": {
|
||||
"context": "product publication date",
|
||||
"string": "Becomes published on {date}"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductMediaNavigation_dot_allMedia": {
|
||||
"context": "section header",
|
||||
"string": "All Media"
|
||||
|
|
130
schema.graphql
130
schema.graphql
|
@ -2152,18 +2152,31 @@ type GatewayConfigLine {
|
|||
|
||||
scalar GenericScalar
|
||||
|
||||
type GiftCard implements Node {
|
||||
code: String
|
||||
user: User
|
||||
created: DateTime!
|
||||
startDate: Date!
|
||||
endDate: Date
|
||||
lastUsedOn: DateTime
|
||||
type GiftCard implements Node & ObjectWithMetadata {
|
||||
code: String!
|
||||
isActive: Boolean!
|
||||
expiryDate: Date
|
||||
expiryType: GiftCardExpiryTypeEnum!
|
||||
tag: String
|
||||
created: DateTime!
|
||||
lastUsedOn: DateTime
|
||||
initialBalance: Money
|
||||
currentBalance: Money
|
||||
id: ID!
|
||||
displayCode: String
|
||||
privateMetadata: [MetadataItem]!
|
||||
metadata: [MetadataItem]!
|
||||
displayCode: String!
|
||||
createdBy: User
|
||||
usedBy: User
|
||||
createdByEmail: String
|
||||
usedByEmail: String
|
||||
app: App
|
||||
expiryPeriod: TimePeriod
|
||||
product: Product
|
||||
events: [GiftCardEvent!]!
|
||||
user: User @deprecated(reason: "Will be removed in Saleor 4.0. Use created_by field instead")
|
||||
endDate: DateTime @deprecated(reason: "Will be removed in Saleor 4.0. Use expiry_date field instead.")
|
||||
startDate: DateTime @deprecated(reason: "Will be removed in Saleor 4.0.")
|
||||
}
|
||||
|
||||
type GiftCardActivate {
|
||||
|
@ -2190,11 +2203,14 @@ type GiftCardCreate {
|
|||
}
|
||||
|
||||
input GiftCardCreateInput {
|
||||
tag: String
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
balance: PositiveDecimal
|
||||
balance: PriceInput!
|
||||
userEmail: String
|
||||
expirySettings: GiftCardExpirySettingsInput!
|
||||
code: String
|
||||
note: String
|
||||
}
|
||||
|
||||
type GiftCardDeactivate {
|
||||
|
@ -2203,6 +2219,12 @@ type GiftCardDeactivate {
|
|||
errors: [GiftCardError!]!
|
||||
}
|
||||
|
||||
type GiftCardDelete {
|
||||
giftCardErrors: [GiftCardError!]! @deprecated(reason: "Use errors field instead. This field will be removed in Saleor 4.0.")
|
||||
errors: [GiftCardError!]!
|
||||
giftCard: GiftCard
|
||||
}
|
||||
|
||||
type GiftCardError {
|
||||
field: String
|
||||
message: String
|
||||
|
@ -2218,6 +2240,66 @@ enum GiftCardErrorCode {
|
|||
UNIQUE
|
||||
}
|
||||
|
||||
type GiftCardEvent implements Node {
|
||||
id: ID!
|
||||
date: DateTime
|
||||
type: GiftCardEventsEnum
|
||||
user: User
|
||||
app: App
|
||||
message: String
|
||||
email: String
|
||||
orderId: ID
|
||||
orderNumber: String
|
||||
tag: String
|
||||
oldTag: String
|
||||
balance: GiftCardEventBalance
|
||||
expiry: GiftCardEventExpiry
|
||||
}
|
||||
|
||||
type GiftCardEventBalance {
|
||||
initialBalance: Money!
|
||||
currentBalance: Money!
|
||||
oldInitialBalance: Money
|
||||
oldCurrentBalance: Money
|
||||
}
|
||||
|
||||
type GiftCardEventExpiry {
|
||||
expiryType: GiftCardExpiryTypeEnum
|
||||
expiryPeriod: TimePeriod
|
||||
expiryDate: Date
|
||||
oldExpiryType: GiftCardExpiryTypeEnum
|
||||
oldExpiryPeriod: TimePeriod
|
||||
oldExpiryDate: Date
|
||||
}
|
||||
|
||||
enum GiftCardEventsEnum {
|
||||
ISSUED
|
||||
BOUGHT
|
||||
UPDATED
|
||||
ACTIVATED
|
||||
DEACTIVATED
|
||||
BALANCE_RESET
|
||||
EXPIRY_SETTINGS_UPDATED
|
||||
SENT_TO_CUSTOMER
|
||||
RESENT
|
||||
}
|
||||
|
||||
input GiftCardExpirySettingsInput {
|
||||
expiryType: GiftCardExpiryTypeEnum!
|
||||
expiryDate: Date
|
||||
expiryPeriod: TimePeriodInputType
|
||||
}
|
||||
|
||||
enum GiftCardExpiryTypeEnum {
|
||||
NEVER_EXPIRE
|
||||
EXPIRY_PERIOD
|
||||
EXPIRY_DATE
|
||||
}
|
||||
|
||||
input GiftCardFilterInput {
|
||||
tag: String
|
||||
}
|
||||
|
||||
type GiftCardUpdate {
|
||||
giftCardErrors: [GiftCardError!]! @deprecated(reason: "Use errors field instead. This field will be removed in Saleor 4.0.")
|
||||
errors: [GiftCardError!]!
|
||||
|
@ -2225,10 +2307,11 @@ type GiftCardUpdate {
|
|||
}
|
||||
|
||||
input GiftCardUpdateInput {
|
||||
tag: String
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
balance: PositiveDecimal
|
||||
userEmail: String
|
||||
balanceAmount: PositiveDecimal
|
||||
expirySettings: GiftCardExpirySettingsInput
|
||||
}
|
||||
|
||||
type Group implements Node {
|
||||
|
@ -2868,6 +2951,7 @@ type Mutation {
|
|||
invoiceSendNotification(id: ID!): InvoiceSendNotification
|
||||
giftCardActivate(id: ID!): GiftCardActivate
|
||||
giftCardCreate(input: GiftCardCreateInput!): GiftCardCreate
|
||||
giftCardDelete(id: ID!): GiftCardDelete
|
||||
giftCardDeactivate(id: ID!): GiftCardDeactivate
|
||||
giftCardUpdate(id: ID!, input: GiftCardUpdateInput!): GiftCardUpdate
|
||||
pluginUpdate(channelId: ID, id: ID!, input: PluginUpdateInput!): PluginUpdate
|
||||
|
@ -4102,6 +4186,11 @@ enum PostalCodeRuleInclusionTypeEnum {
|
|||
EXCLUDE
|
||||
}
|
||||
|
||||
input PriceInput {
|
||||
currency: String!
|
||||
amount: PositiveDecimal!
|
||||
}
|
||||
|
||||
input PriceRangeInput {
|
||||
gte: Float
|
||||
lte: Float
|
||||
|
@ -4787,7 +4876,7 @@ type Query {
|
|||
menuItem(id: ID!, channel: String): MenuItem
|
||||
menuItems(channel: String, sortBy: MenuItemSortingInput, filter: MenuItemFilterInput, before: String, after: String, first: Int, last: Int): MenuItemCountableConnection
|
||||
giftCard(id: ID!): GiftCard
|
||||
giftCards(before: String, after: String, first: Int, last: Int): GiftCardCountableConnection
|
||||
giftCards(filter: GiftCardFilterInput, before: String, after: String, first: Int, last: Int): GiftCardCountableConnection
|
||||
plugin(id: ID!): Plugin
|
||||
plugins(filter: PluginFilterInput, sortBy: PluginSortingInput, before: String, after: String, first: Int, last: Int): PluginCountableConnection
|
||||
sale(id: ID!, channel: String): Sale
|
||||
|
@ -5258,6 +5347,7 @@ type Shop {
|
|||
availablePaymentGateways(currency: String, channel: String): [PaymentGateway!]!
|
||||
availableExternalAuthentications: [ExternalAuthentication!]!
|
||||
availableShippingMethods(channel: String!, address: AddressInput): [ShippingMethod]
|
||||
channelCurrencies: [String!]!
|
||||
countries(languageCode: LanguageCodeEnum): [CountryDisplay!]!
|
||||
defaultCountry: CountryDisplay
|
||||
defaultMailSenderName: String
|
||||
|
@ -5525,6 +5615,22 @@ type TaxedMoneyRange {
|
|||
stop: TaxedMoney
|
||||
}
|
||||
|
||||
type TimePeriod {
|
||||
amount: Int!
|
||||
type: TimePeriodTypeEnum!
|
||||
}
|
||||
|
||||
input TimePeriodInputType {
|
||||
amount: Int!
|
||||
type: TimePeriodTypeEnum!
|
||||
}
|
||||
|
||||
enum TimePeriodTypeEnum {
|
||||
DAY
|
||||
MONTH
|
||||
YEAR
|
||||
}
|
||||
|
||||
type Transaction implements Node {
|
||||
id: ID!
|
||||
created: DateTime!
|
||||
|
|
23
src/apps/components/VerticalSpacer/VerticalSpacer.tsx
Normal file
23
src/apps/components/VerticalSpacer/VerticalSpacer.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
|
||||
export interface VerticalSpacerProps {
|
||||
spacing?: number;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
container: ({ spacing }: VerticalSpacerProps) => ({
|
||||
height: theme.spacing(spacing)
|
||||
})
|
||||
}),
|
||||
{ name: "VerticalSpacer" }
|
||||
);
|
||||
|
||||
const VerticalSpacer: React.FC<VerticalSpacerProps> = ({ spacing = 1 }) => {
|
||||
const classes = useStyles({ spacing });
|
||||
|
||||
return <div className={classes.container} />;
|
||||
};
|
||||
|
||||
export default VerticalSpacer;
|
2
src/apps/components/VerticalSpacer/index.tsx
Normal file
2
src/apps/components/VerticalSpacer/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./VerticalSpacer";
|
||||
export { default } from "./VerticalSpacer";
|
|
@ -2,7 +2,7 @@ import { DEMO_MODE } from "@saleor/config";
|
|||
import { User } from "@saleor/fragments/types/User";
|
||||
import { SetLocalStorage } from "@saleor/hooks/useLocalStorage";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { getMutationStatus } from "@saleor/misc";
|
||||
import { getFullName, getMutationStatus } from "@saleor/misc";
|
||||
import errorTracker from "@saleor/services/errorTracking";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useMutation } from "react-apollo";
|
||||
|
@ -88,11 +88,11 @@ export function useExternalAuthProvider({
|
|||
|
||||
useEffect(() => {
|
||||
if (authPlugin && userContext) {
|
||||
const { id, email, firstName, lastName } = userContext;
|
||||
const { id, email } = userContext;
|
||||
errorTracker.setUserData({
|
||||
email,
|
||||
id,
|
||||
username: `${firstName} ${lastName}`
|
||||
username: getFullName(userContext)
|
||||
});
|
||||
|
||||
if (!userContext.isStaff) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { DEMO_MODE } from "@saleor/config";
|
|||
import { User } from "@saleor/fragments/types/User";
|
||||
import { SetLocalStorage } from "@saleor/hooks/useLocalStorage";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { getMutationStatus } from "@saleor/misc";
|
||||
import { getFullName, getMutationStatus } from "@saleor/misc";
|
||||
import errorTracker from "@saleor/services/errorTracking";
|
||||
import {
|
||||
isSupported as isCredentialsManagementAPISupported,
|
||||
|
@ -66,11 +66,11 @@ export function useSaleorAuthProvider({
|
|||
|
||||
useEffect(() => {
|
||||
if (!authPlugin && userContext) {
|
||||
const { id, email, firstName, lastName } = userContext;
|
||||
const { id, email } = userContext;
|
||||
errorTracker.setUserData({
|
||||
email,
|
||||
id,
|
||||
username: `${firstName} ${lastName}`
|
||||
username: getFullName(userContext)
|
||||
});
|
||||
|
||||
if (!userContext.isStaff) {
|
||||
|
|
|
@ -56,11 +56,11 @@ export function createFilterStructure(
|
|||
...createOptionsField(
|
||||
CollectionFilterKeys.channel,
|
||||
intl.formatMessage(commonMessages.channel),
|
||||
[opts.channel.value],
|
||||
[opts.channel?.value],
|
||||
false,
|
||||
opts.channel.choices
|
||||
opts.channel?.choices
|
||||
),
|
||||
active: opts.channel.active
|
||||
active: opts.channel?.active
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
@ -65,4 +65,5 @@ export interface CollectionListVariables {
|
|||
before?: string | null;
|
||||
filter?: CollectionFilterInput | null;
|
||||
sort?: CollectionSortingInput | null;
|
||||
channel?: string | null;
|
||||
}
|
||||
|
|
|
@ -115,7 +115,6 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
const filterOpts = getFilterOpts(params, channelOpts);
|
||||
const tabs = getFilterTabs();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
exports[`Filtering URL params should not be empty if active filters are present 1`] = `
|
||||
Object {
|
||||
"channel": undefined,
|
||||
"status": "PUBLISHED",
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -4,14 +4,14 @@ import React from "react";
|
|||
|
||||
import { ConfirmButtonTransitionState } from "../ConfirmButton";
|
||||
import DialogButtons from "./DialogButtons";
|
||||
import { ActionDialogVariant } from "./types";
|
||||
import { ActionDialogVariant, Size } from "./types";
|
||||
|
||||
interface ActionDialogProps extends DialogProps {
|
||||
children?: React.ReactNode;
|
||||
confirmButtonLabel?: string;
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
disabled?: boolean;
|
||||
maxWidth?: "xs" | "sm" | "md" | "lg" | "xl" | false;
|
||||
maxWidth?: Size | false;
|
||||
title: string;
|
||||
variant?: ActionDialogVariant;
|
||||
onConfirm();
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
export type ActionDialogVariant = "default" | "delete" | "info";
|
||||
|
||||
export type Size = "xs" | "sm" | "md" | "lg" | "xl";
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
useSavebar,
|
||||
useTheme
|
||||
} from "@saleor/macaw-ui";
|
||||
import { isDarkTheme } from "@saleor/misc";
|
||||
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
@ -154,8 +155,7 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
|||
});
|
||||
};
|
||||
|
||||
const isDark = themeType === "dark";
|
||||
const toggleTheme = () => setTheme(isDark ? "light" : "dark");
|
||||
const toggleTheme = () => setTheme(isDarkTheme(themeType) ? "light" : "dark");
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -203,7 +203,7 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
|||
/>
|
||||
)}
|
||||
<UserChip
|
||||
isDarkThemeEnabled={isDark}
|
||||
isDarkThemeEnabled={isDarkTheme(themeType)}
|
||||
user={user}
|
||||
onLogout={logout}
|
||||
onProfileClick={() =>
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from "@saleor/configuration";
|
||||
import { MenuItem } from "@saleor/configuration/ConfigurationPage";
|
||||
import { User } from "@saleor/fragments/types/User";
|
||||
import { giftCardsListUrl } from "@saleor/giftCards/urls";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { SidebarMenuItem } from "@saleor/macaw-ui";
|
||||
import { IntlShape } from "react-intl";
|
||||
|
@ -62,6 +63,12 @@ function createMenuStructure(intl: IntlShape, user: User): SidebarMenuItem[] {
|
|||
label: intl.formatMessage(sectionNames.collections),
|
||||
id: "collections",
|
||||
url: collectionListUrl()
|
||||
},
|
||||
{
|
||||
ariaLabel: "giftCards",
|
||||
label: intl.formatMessage(sectionNames.giftCards),
|
||||
id: "giftCards",
|
||||
url: giftCardsListUrl()
|
||||
}
|
||||
],
|
||||
iconSrc: catalogIcon,
|
||||
|
|
11
src/components/DeleteIconButton/DeleteIconButton.tsx
Normal file
11
src/components/DeleteIconButton/DeleteIconButton.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { IconButton, IconButtonProps } from "@material-ui/core";
|
||||
import TrashIcon from "@saleor/icons/Trash";
|
||||
import React from "react";
|
||||
|
||||
const DeleteIconButton: React.FC<IconButtonProps> = ({ onClick }) => (
|
||||
<IconButton color="primary" onClick={onClick}>
|
||||
<TrashIcon />
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
export default DeleteIconButton;
|
2
src/components/DeleteIconButton/index.tsx
Normal file
2
src/components/DeleteIconButton/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./DeleteIconButton";
|
||||
export { default } from "./DeleteIconButton";
|
|
@ -1,35 +1,43 @@
|
|||
import { makeStyles, Typography, TypographyProps } from "@material-ui/core";
|
||||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||
import React from "react";
|
||||
|
||||
import { LocaleConsumer } from "../Locale";
|
||||
|
||||
export interface IMoney {
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
export interface MoneyProps {
|
||||
|
||||
export interface MoneyProps extends TypographyProps {
|
||||
money: IMoney | null;
|
||||
}
|
||||
|
||||
export const formatMoney = (money: IMoney, locale: string) => {
|
||||
try {
|
||||
const formattedMoney = money.amount.toLocaleString(locale, {
|
||||
currency: money.currency,
|
||||
style: "currency"
|
||||
});
|
||||
return formattedMoney;
|
||||
} catch (error) {
|
||||
return `${money.amount} ${money.currency}`;
|
||||
const useStyles = makeStyles(
|
||||
() => ({
|
||||
container: {
|
||||
display: "flex",
|
||||
alignItems: "baseline"
|
||||
}
|
||||
};
|
||||
|
||||
export const Money: React.FC<MoneyProps> = ({ money }) =>
|
||||
money ? (
|
||||
<LocaleConsumer>
|
||||
{({ locale }) => formatMoney(money, locale)}
|
||||
</LocaleConsumer>
|
||||
) : (
|
||||
<>-</>
|
||||
}),
|
||||
{ name: "Money" }
|
||||
);
|
||||
|
||||
export const Money: React.FC<MoneyProps> = ({ money, ...rest }) => {
|
||||
const classes = useStyles({});
|
||||
|
||||
if (!money) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<Typography variant="caption" {...rest}>
|
||||
{money.currency}
|
||||
</Typography>
|
||||
<HorizontalSpacer spacing={0.5} />
|
||||
<Typography {...rest}>{money.amount.toFixed(2)}</Typography>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Money.displayName = "Money";
|
||||
export default Money;
|
||||
|
|
|
@ -15,3 +15,15 @@ export function subtractMoney(init: IMoney, ...args: IMoney[]): IMoney {
|
|||
currency: init.currency
|
||||
};
|
||||
}
|
||||
|
||||
export const formatMoney = (money: IMoney, locale: string) => {
|
||||
try {
|
||||
const formattedMoney = money.amount.toLocaleString(locale, {
|
||||
currency: money.currency,
|
||||
style: "currency"
|
||||
});
|
||||
return formattedMoney;
|
||||
} catch (error) {
|
||||
return `${money.amount} ${money.currency}`;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -30,9 +30,10 @@ const useStyles = makeStyles(
|
|||
marginTop: theme.spacing(2),
|
||||
padding: 0
|
||||
},
|
||||
fontWeight: 700,
|
||||
alignSelf: "flex-start",
|
||||
flex: 1,
|
||||
fontSize: 24
|
||||
fontSize: 48
|
||||
}
|
||||
}),
|
||||
{ name: "PageHeader" }
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||
import StatusChip from "@saleor/components/StatusChip";
|
||||
import { StatusType } from "@saleor/components/StatusChip/types";
|
||||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
|
||||
export interface PageTitleWithStatusChipProps {
|
||||
title: string;
|
||||
statusLabel: string;
|
||||
statusType: StatusType;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
() => ({
|
||||
container: {
|
||||
alignItems: "center",
|
||||
display: "flex"
|
||||
}
|
||||
}),
|
||||
{ name: "OrderDetailsPageTitleWithStatusChip" }
|
||||
);
|
||||
|
||||
const PageTitleWithStatusChip: React.FC<PageTitleWithStatusChipProps> = ({
|
||||
title,
|
||||
statusLabel,
|
||||
statusType
|
||||
}) => {
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
{title}
|
||||
<HorizontalSpacer spacing={2} />
|
||||
<StatusChip label={statusLabel} status={statusType} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageTitleWithStatusChip;
|
2
src/components/PageTitleWithStatusChip/index.tsx
Normal file
2
src/components/PageTitleWithStatusChip/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./PageTitleWithStatusChip";
|
||||
export { default } from "./PageTitleWithStatusChip";
|
|
@ -13,6 +13,7 @@ const shopInfo = gql`
|
|||
country
|
||||
code
|
||||
}
|
||||
channelCurrencies
|
||||
defaultCountry {
|
||||
code
|
||||
country
|
||||
|
|
|
@ -42,6 +42,7 @@ export interface ShopInfo_shop_permissions {
|
|||
export interface ShopInfo_shop {
|
||||
__typename: "Shop";
|
||||
countries: ShopInfo_shop_countries[];
|
||||
channelCurrencies: string[];
|
||||
defaultCountry: ShopInfo_shop_defaultCountry | null;
|
||||
defaultWeightUnit: WeightUnitsEnum | null;
|
||||
displayGrossPrices: boolean;
|
||||
|
|
|
@ -33,14 +33,17 @@ interface SkeletonProps {
|
|||
className?: string;
|
||||
primary?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const Skeleton: React.FC<SkeletonProps> = props => {
|
||||
const { className, primary, style } = props;
|
||||
const { className, primary, style, children } = props;
|
||||
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
return children ? (
|
||||
(children as React.ReactElement)
|
||||
) : (
|
||||
<span
|
||||
data-test-id="skeleton"
|
||||
className={classNames(classes.skeleton, className, {
|
||||
|
|
|
@ -7,7 +7,11 @@ import { StatusType } from "./types";
|
|||
|
||||
storiesOf("Generics / Status Chip", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("neutral", () => <StatusChip label="label" type={StatusType.NEUTRAL} />)
|
||||
.add("error", () => <StatusChip label="label" type={StatusType.ERROR} />)
|
||||
.add("success", () => <StatusChip label="label" type={StatusType.SUCCESS} />)
|
||||
.add("alert", () => <StatusChip label="label" type={StatusType.ALERT} />);
|
||||
.add("neutral", () => (
|
||||
<StatusChip label="label" status={StatusType.NEUTRAL} />
|
||||
))
|
||||
.add("error", () => <StatusChip label="label" status={StatusType.ERROR} />)
|
||||
.add("success", () => (
|
||||
<StatusChip label="label" status={StatusType.SUCCESS} />
|
||||
))
|
||||
.add("alert", () => <StatusChip label="label" status={StatusType.ALERT} />);
|
||||
|
|
|
@ -3,14 +3,16 @@ import { makeStyles } from "@saleor/macaw-ui";
|
|||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
||||
import { Size } from "../ActionDialog/types";
|
||||
import { StatusType } from "./types";
|
||||
|
||||
export interface StatusChipProps {
|
||||
type?: StatusType;
|
||||
status?: StatusType;
|
||||
size?: Size;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
const StatusChipStyles = {
|
||||
export const statusChipStyles = {
|
||||
alert: {
|
||||
background: "#FFF4E4"
|
||||
},
|
||||
|
@ -34,28 +36,38 @@ const StatusChipStyles = {
|
|||
},
|
||||
successLabel: {
|
||||
color: "#5DC292"
|
||||
},
|
||||
lg: {
|
||||
padding: "4px 16px"
|
||||
},
|
||||
lgLabel: {
|
||||
fontSize: "1.5rem"
|
||||
},
|
||||
md: {
|
||||
padding: "4px 16px"
|
||||
},
|
||||
mdLabel: {
|
||||
fontSize: 16
|
||||
}
|
||||
};
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
label: {
|
||||
fontSize: theme.typography.body1.fontSize,
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
textTransform: "uppercase"
|
||||
},
|
||||
root: {
|
||||
borderRadius: 22,
|
||||
display: "inline-block",
|
||||
padding: "8px 24px"
|
||||
display: "inline-block"
|
||||
},
|
||||
...StatusChipStyles
|
||||
...statusChipStyles
|
||||
}),
|
||||
{ name: "StatusChip" }
|
||||
);
|
||||
|
||||
const StatusChip: React.FC<StatusChipProps> = props => {
|
||||
const { type = StatusType.NEUTRAL, label } = props;
|
||||
const { status = StatusType.NEUTRAL, size = "lg", label } = props;
|
||||
const classes = useStyles(props);
|
||||
|
||||
if (!label) {
|
||||
|
@ -63,9 +75,13 @@ const StatusChip: React.FC<StatusChipProps> = props => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className={classNames(classes.root, classes[type])}>
|
||||
<div className={classNames(classes.root, classes[status], classes[size])}>
|
||||
<Typography
|
||||
className={classNames(classes.label, classes[`${type}Label`])}
|
||||
className={classNames(
|
||||
classes.label,
|
||||
classes[`${status}Label`],
|
||||
classes[`${size}Label`]
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
|
|
|
@ -3,6 +3,7 @@ import { fade } from "@material-ui/core/styles/colorManipulator";
|
|||
import ArrowLeft from "@material-ui/icons/ArrowLeft";
|
||||
import ArrowRight from "@material-ui/icons/ArrowRight";
|
||||
import { makeStyles, useTheme } from "@saleor/macaw-ui";
|
||||
import { isDarkTheme } from "@saleor/misc";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
||||
|
@ -76,7 +77,7 @@ export const TablePaginationActions: React.FC<TablePaginationActionsProps> = pro
|
|||
|
||||
const { direction, themeType } = useTheme();
|
||||
|
||||
const isDark = themeType === "dark";
|
||||
const isDark = isDarkTheme(themeType);
|
||||
|
||||
return (
|
||||
<div className={classNames(classes.root, className)} {...other}>
|
||||
|
|
125
src/components/TextWithSelectField/TextWithSelectField.tsx
Normal file
125
src/components/TextWithSelectField/TextWithSelectField.tsx
Normal file
|
@ -0,0 +1,125 @@
|
|||
import { TextField } from "@material-ui/core";
|
||||
import SingleSelectField, {
|
||||
Choices
|
||||
} from "@saleor/components/SingleSelectField";
|
||||
import { ChangeEvent, FormChange } from "@saleor/hooks/useForm";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
interface CommonFieldProps {
|
||||
name: string;
|
||||
type?: string;
|
||||
className?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export interface TextWithSelectFieldProps {
|
||||
change: FormChange;
|
||||
choices: Choices;
|
||||
helperText?: string;
|
||||
isError?: boolean;
|
||||
textFieldProps: CommonFieldProps & {
|
||||
value?: string | number;
|
||||
minValue?: number;
|
||||
};
|
||||
selectFieldProps: CommonFieldProps & { value: string };
|
||||
containerClassName?: string;
|
||||
}
|
||||
|
||||
const TextWithSelectField: React.FC<TextWithSelectFieldProps> = ({
|
||||
change,
|
||||
choices,
|
||||
containerClassName,
|
||||
textFieldProps,
|
||||
selectFieldProps,
|
||||
helperText,
|
||||
isError
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const {
|
||||
name: textFieldName,
|
||||
value: textFieldValue,
|
||||
label: textFieldLabel,
|
||||
type: textFieldType,
|
||||
minValue: textFieldMinValue
|
||||
} = textFieldProps;
|
||||
|
||||
const {
|
||||
name: selectFieldName,
|
||||
value: selectFieldValue,
|
||||
className: selectFieldClassName
|
||||
} = selectFieldProps;
|
||||
|
||||
const handleSelectChange = (event: ChangeEvent) => {
|
||||
// in case one of the fields in the form is empty
|
||||
// we need to save the other part of the field as well
|
||||
const otherTarget = {
|
||||
value: textFieldValue,
|
||||
name: textFieldName
|
||||
};
|
||||
|
||||
change(event);
|
||||
change({ target: otherTarget });
|
||||
};
|
||||
|
||||
const handleTextChange = (event: ChangeEvent) => {
|
||||
const { value } = event.target;
|
||||
|
||||
const otherTarget = {
|
||||
value: selectFieldValue,
|
||||
name: selectFieldName
|
||||
};
|
||||
|
||||
// handle parsing in case of text field of type number
|
||||
const parsedValue =
|
||||
textFieldType === "number" && typeof value === "string"
|
||||
? parseInt(value, 10)
|
||||
: value;
|
||||
|
||||
change({
|
||||
...event,
|
||||
target: { ...event.target, value: parsedValue, name: event.target.name }
|
||||
});
|
||||
change({ target: otherTarget });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={containerClassName || classes.container}>
|
||||
<TextField
|
||||
error={isError}
|
||||
helperText={helperText}
|
||||
type="number"
|
||||
className={classes.innerContainer}
|
||||
name={textFieldName}
|
||||
label={textFieldLabel}
|
||||
inputProps={{
|
||||
min: textFieldMinValue
|
||||
}}
|
||||
InputProps={{
|
||||
className: classNames(classes.textField, {
|
||||
[classes.textFieldCentered]: !textFieldLabel
|
||||
}),
|
||||
endAdornment: (
|
||||
<SingleSelectField
|
||||
name={selectFieldName}
|
||||
onChange={handleSelectChange}
|
||||
value={selectFieldValue}
|
||||
className={classNames(
|
||||
classes.autocompleteField,
|
||||
selectFieldClassName
|
||||
)}
|
||||
choices={choices}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
onChange={handleTextChange}
|
||||
value={textFieldValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TextWithSelectField;
|
2
src/components/TextWithSelectField/index.tsx
Normal file
2
src/components/TextWithSelectField/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./TextWithSelectField";
|
||||
export { default } from "./TextWithSelectField";
|
36
src/components/TextWithSelectField/styles.ts
Normal file
36
src/components/TextWithSelectField/styles.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
() => ({
|
||||
container: {
|
||||
width: 400
|
||||
},
|
||||
innerContainer: {
|
||||
width: "100%"
|
||||
},
|
||||
textField: {
|
||||
width: "100%",
|
||||
paddingRight: 0,
|
||||
"& input": {
|
||||
maxWidth: "100%"
|
||||
}
|
||||
},
|
||||
textFieldCentered: {
|
||||
"& input": {
|
||||
paddingTop: 16,
|
||||
paddingBottom: 16
|
||||
}
|
||||
},
|
||||
autocompleteField: {
|
||||
height: 52,
|
||||
border: "none",
|
||||
"& *": {
|
||||
border: "none"
|
||||
},
|
||||
"& *:focus": {
|
||||
background: "none"
|
||||
}
|
||||
}
|
||||
}),
|
||||
{ name: "TextWithSelectField" }
|
||||
);
|
|
@ -22,6 +22,7 @@ export const PAGINATE_BY = 20;
|
|||
export const VALUES_PAGINATE_BY = 10;
|
||||
|
||||
export type ProductListColumns = "productType" | "availability" | "price";
|
||||
|
||||
export interface AppListViewSettings {
|
||||
[ListViews.APPS_LIST]: ListSettings;
|
||||
[ListViews.ATTRIBUTE_VALUE_LIST]: ListSettings;
|
||||
|
@ -42,7 +43,9 @@ export interface AppListViewSettings {
|
|||
[ListViews.WAREHOUSE_LIST]: ListSettings;
|
||||
[ListViews.WEBHOOK_LIST]: ListSettings;
|
||||
[ListViews.TRANSLATION_ATTRIBUTE_VALUE_LIST]: ListSettings;
|
||||
[ListViews.GIFT_CARD_LIST]: ListSettings;
|
||||
}
|
||||
|
||||
export const defaultListSettings: AppListViewSettings = {
|
||||
[ListViews.APPS_LIST]: {
|
||||
rowNumber: 10
|
||||
|
@ -101,10 +104,14 @@ export const defaultListSettings: AppListViewSettings = {
|
|||
},
|
||||
[ListViews.TRANSLATION_ATTRIBUTE_VALUE_LIST]: {
|
||||
rowNumber: 10
|
||||
},
|
||||
[ListViews.GIFT_CARD_LIST]: {
|
||||
rowNumber: PAGINATE_BY
|
||||
}
|
||||
};
|
||||
|
||||
export const APP_VERSION = packageInfo.version;
|
||||
|
||||
export const DEMO_MODE = process.env.DEMO_MODE === "true";
|
||||
export const GTM_ID = process.env.GTM_ID;
|
||||
|
||||
|
|
|
@ -13,4 +13,4 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`Filtering URL params should not be empty if active filters are present 2`] = `"channel=default-channel&startedFrom=2019-12-09&startedTo=2019-12-38&status%5B0%5D=ACTIVE&status%5B1%5D=EXPIRED&type=FIXED"`;
|
||||
exports[`Filtering URL params should not be empty if active filters are present 2`] = `"channel=default-channel&startedFrom=2019-12-09&startedTo=2019-12-38&status%5B%5D=ACTIVE&status%5B%5D=EXPIRED&type=FIXED"`;
|
||||
|
|
|
@ -18,4 +18,4 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`Filtering URL params should not be empty if active filters are present 2`] = `"channel=default-channel&startedFrom=2019-12-09&startedTo=2019-12-38×UsedFrom=1×UsedTo=6&status%5B0%5D=ACTIVE&status%5B1%5D=EXPIRED&type%5B0%5D=FIXED&type%5B1%5D=SHIPPING"`;
|
||||
exports[`Filtering URL params should not be empty if active filters are present 2`] = `"channel=default-channel&startedFrom=2019-12-09&startedTo=2019-12-38×UsedFrom=1×UsedTo=6&status%5B%5D=ACTIVE&status%5B%5D=EXPIRED&type%5B%5D=FIXED&type%5B%5D=SHIPPING"`;
|
||||
|
|
|
@ -16,3 +16,11 @@ export const fragmentUser = gql`
|
|||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const fragmentUserBase = gql`
|
||||
fragment UserBase on User {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -215,3 +215,10 @@ export const uploadErrorFragment = gql`
|
|||
field
|
||||
}
|
||||
`;
|
||||
|
||||
export const giftCardErrorFragment = gql`
|
||||
fragment GiftCardError on GiftCardError {
|
||||
code
|
||||
field
|
||||
}
|
||||
`;
|
||||
|
|
8
src/fragments/timePeriod.ts
Normal file
8
src/fragments/timePeriod.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import gql from "graphql-tag";
|
||||
|
||||
export const fragmentTimePeriod = gql`
|
||||
fragment TimePeriod on TimePeriod {
|
||||
amount
|
||||
type
|
||||
}
|
||||
`;
|
16
src/fragments/types/GiftCardError.ts
Normal file
16
src/fragments/types/GiftCardError.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: GiftCardError
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardError {
|
||||
__typename: "GiftCardError";
|
||||
code: GiftCardErrorCode;
|
||||
field: string | null;
|
||||
}
|
|
@ -20,7 +20,7 @@ export interface MetadataFragment_privateMetadata {
|
|||
}
|
||||
|
||||
export interface MetadataFragment {
|
||||
__typename: "App" | "Warehouse" | "ShippingZone" | "ShippingMethod" | "Product" | "ProductType" | "Attribute" | "Category" | "ProductVariant" | "DigitalContent" | "Collection" | "Page" | "PageType" | "Sale" | "Voucher" | "MenuItem" | "Menu" | "User" | "Checkout" | "Order" | "Fulfillment" | "Invoice";
|
||||
__typename: "App" | "Warehouse" | "ShippingZone" | "ShippingMethod" | "Product" | "ProductType" | "Attribute" | "Category" | "ProductVariant" | "DigitalContent" | "Collection" | "Page" | "PageType" | "Sale" | "Voucher" | "MenuItem" | "Menu" | "User" | "Checkout" | "GiftCard" | "Order" | "Fulfillment" | "Invoice";
|
||||
metadata: (MetadataFragment_metadata | null)[];
|
||||
privateMetadata: (MetadataFragment_privateMetadata | null)[];
|
||||
}
|
||||
|
|
16
src/fragments/types/TimePeriod.ts
Normal file
16
src/fragments/types/TimePeriod.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { TimePeriodTypeEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: TimePeriod
|
||||
// ====================================================
|
||||
|
||||
export interface TimePeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
15
src/fragments/types/UserBase.ts
Normal file
15
src/fragments/types/UserBase.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: UserBase
|
||||
// ====================================================
|
||||
|
||||
export interface UserBase {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
114
src/giftCards/GiftCardCreateDialog/GiftCardCreateDialog.tsx
Normal file
114
src/giftCards/GiftCardCreateDialog/GiftCardCreateDialog.tsx
Normal file
|
@ -0,0 +1,114 @@
|
|||
import { Dialog, DialogTitle } from "@material-ui/core";
|
||||
import { IMessage } from "@saleor/components/messages";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import { GiftCardCreateInput } from "@saleor/types/globalTypes";
|
||||
import commonErrorMessages from "@saleor/utils/errors/common";
|
||||
import React, { useState } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import GiftCardCreateDialogCodeContent from "./GiftCardCreateDialogCodeContent";
|
||||
import GiftCardCreateDialogForm, {
|
||||
GiftCardCreateFormData
|
||||
} from "./GiftCardCreateDialogForm";
|
||||
import { giftCardCreateDialogMessages as messages } from "./messages";
|
||||
import { useGiftCardCreateMutation } from "./mutations";
|
||||
import { GiftCardCreate } from "./types/GiftCardCreate";
|
||||
import { getGiftCardExpirySettingsInputData } from "./utils";
|
||||
|
||||
interface GiftCardCreateDialogProps {
|
||||
onClose: () => void;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
const GiftCardCreateDialog: React.FC<GiftCardCreateDialogProps> = ({
|
||||
onClose,
|
||||
open
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const notify = useNotifier();
|
||||
|
||||
const [cardCode, setCardCode] = useState(null);
|
||||
|
||||
const onCompleted = (data: GiftCardCreate) => {
|
||||
const errors = data?.giftCardCreate?.errors;
|
||||
|
||||
const notifierData: IMessage = !!errors?.length
|
||||
? {
|
||||
status: "error",
|
||||
text: intl.formatMessage(commonErrorMessages.unknownError)
|
||||
}
|
||||
: {
|
||||
status: "success",
|
||||
text: intl.formatMessage(messages.createdSuccessAlertTitle)
|
||||
};
|
||||
|
||||
notify(notifierData);
|
||||
|
||||
if (!errors?.length) {
|
||||
setCardCode(data?.giftCardCreate?.giftCard?.code);
|
||||
}
|
||||
};
|
||||
|
||||
const getParsedSubmitInputData = (
|
||||
formData: GiftCardCreateFormData
|
||||
): GiftCardCreateInput => {
|
||||
const {
|
||||
balanceAmount,
|
||||
balanceCurrency,
|
||||
note,
|
||||
tag,
|
||||
selectedCustomer
|
||||
} = formData;
|
||||
|
||||
return {
|
||||
note: note || null,
|
||||
tag: tag || null,
|
||||
userEmail: selectedCustomer.email || null,
|
||||
balance: {
|
||||
amount: balanceAmount,
|
||||
currency: balanceCurrency
|
||||
},
|
||||
expirySettings: getGiftCardExpirySettingsInputData(formData)
|
||||
};
|
||||
};
|
||||
|
||||
const [createGiftCard, createGiftCardOpts] = useGiftCardCreateMutation({
|
||||
onCompleted
|
||||
});
|
||||
|
||||
const handleSubmit = (data: GiftCardCreateFormData) => {
|
||||
createGiftCard({
|
||||
variables: {
|
||||
input: getParsedSubmitInputData(data)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
// dialog closing animation runs slower than prop change
|
||||
// and we don't want to show the form for a split second
|
||||
setTimeout(() => setCardCode(null), 0);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} maxWidth="sm">
|
||||
<DialogTitle>{intl.formatMessage(messages.title)}</DialogTitle>
|
||||
{cardCode ? (
|
||||
<GiftCardCreateDialogCodeContent
|
||||
cardCode={cardCode}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
) : (
|
||||
<GiftCardCreateDialogForm
|
||||
opts={createGiftCardOpts}
|
||||
onClose={handleClose}
|
||||
apiErrors={createGiftCardOpts?.data?.giftCardCreate?.errors}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardCreateDialog;
|
|
@ -0,0 +1,58 @@
|
|||
import { Button, DialogContent, Typography } from "@material-ui/core";
|
||||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||
import VerticalSpacer from "@saleor/apps/components/VerticalSpacer";
|
||||
import useClipboard from "@saleor/hooks/useClipboard";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import { buttonMessages } from "@saleor/intl";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { giftCardCreateDialogMessages as messages } from "./messages";
|
||||
import { useGiftCardCreateDialogCodeContentStyles as useStyles } from "./styles";
|
||||
|
||||
interface GiftCardCreateDialogCodeContentProps {
|
||||
cardCode: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const GiftCardCreateDialogCodeContent: React.FC<GiftCardCreateDialogCodeContentProps> = ({
|
||||
cardCode,
|
||||
onClose
|
||||
}) => {
|
||||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
const notify = useNotifier();
|
||||
const [, copy] = useClipboard();
|
||||
|
||||
const onCopyCode = () => {
|
||||
copy(cardCode);
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage(messages.copiedToClipboardTitle)
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogContent>
|
||||
<Typography>
|
||||
{intl.formatMessage(messages.createdGiftCardLabel)}
|
||||
</Typography>
|
||||
<VerticalSpacer />
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
{cardCode}
|
||||
</Typography>
|
||||
<VerticalSpacer spacing={2} />
|
||||
<div className={classes.buttonsContainer}>
|
||||
<Button onClick={onCopyCode}>
|
||||
{intl.formatMessage(messages.copyCodeLabel)}
|
||||
</Button>
|
||||
<HorizontalSpacer spacing={2} />
|
||||
<Button color="primary" variant="contained" onClick={onClose}>
|
||||
{intl.formatMessage(buttonMessages.ok)}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardCreateDialogCodeContent;
|
172
src/giftCards/GiftCardCreateDialog/GiftCardCreateDialogForm.tsx
Normal file
172
src/giftCards/GiftCardCreateDialog/GiftCardCreateDialogForm.tsx
Normal file
|
@ -0,0 +1,172 @@
|
|||
import { DialogContent, Divider, TextField } from "@material-ui/core";
|
||||
import VerticalSpacer from "@saleor/apps/components/VerticalSpacer";
|
||||
import DialogButtons from "@saleor/components/ActionDialog/DialogButtons";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import TextWithSelectField from "@saleor/components/TextWithSelectField";
|
||||
import { GiftCardError } from "@saleor/fragments/types/GiftCardError";
|
||||
import GiftCardExpirySelect from "@saleor/giftCards/components/GiftCardExpirySelect";
|
||||
import GiftCardTagInput from "@saleor/giftCards/components/GiftCardTagInput";
|
||||
import useForm from "@saleor/hooks/useForm";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||
import Label from "@saleor/orders/components/OrderHistory/Label";
|
||||
import {
|
||||
GiftCardExpiryTypeEnum,
|
||||
TimePeriodTypeEnum
|
||||
} from "@saleor/types/globalTypes";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import { mapSingleValueNodeToChoice } from "@saleor/utils/maps";
|
||||
import React, { useState } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { getGiftCardErrorMessage } from "../GiftCardUpdate/messages";
|
||||
import GiftCardCustomerSelectField from "./GiftCardCustomerSelectField";
|
||||
import { giftCardCreateDialogMessages as messages } from "./messages";
|
||||
import { useGiftCardCreateDialogFormStyles as useStyles } from "./styles";
|
||||
import { GiftCardCommonFormData, GiftCardCreateFormCustomer } from "./types";
|
||||
|
||||
export interface GiftCardCreateFormData extends GiftCardCommonFormData {
|
||||
note: string;
|
||||
selectedCustomer?: GiftCardCreateFormCustomer;
|
||||
}
|
||||
|
||||
const initialCustomer = { email: "", name: "" };
|
||||
|
||||
export const initialData: GiftCardCreateFormData = {
|
||||
tag: "",
|
||||
balanceAmount: 1,
|
||||
balanceCurrency: null,
|
||||
note: "",
|
||||
expiryDate: "",
|
||||
expiryType: GiftCardExpiryTypeEnum.EXPIRY_PERIOD,
|
||||
expiryPeriodType: TimePeriodTypeEnum.YEAR,
|
||||
expiryPeriodAmount: 1
|
||||
};
|
||||
|
||||
interface GiftCardCreateDialogFormProps {
|
||||
opts: { status: ConfirmButtonTransitionState };
|
||||
apiErrors: GiftCardError[];
|
||||
onSubmit: (data: GiftCardCreateFormData) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const GiftCardCreateDialogForm: React.FC<GiftCardCreateDialogFormProps> = ({
|
||||
onSubmit,
|
||||
opts,
|
||||
onClose,
|
||||
apiErrors
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
const shop = useShop();
|
||||
|
||||
// TEMP
|
||||
const initialCurrency = shop?.channelCurrencies?.[0];
|
||||
|
||||
const [selectedCustomer, setSelectedCustomer] = useState<
|
||||
GiftCardCreateFormCustomer
|
||||
>(initialCustomer);
|
||||
|
||||
const handleSubmit = (data: GiftCardCreateFormData) =>
|
||||
onSubmit({ ...data, selectedCustomer });
|
||||
|
||||
const { submit, change, data } = useForm(
|
||||
{ ...initialData, balanceCurrency: initialCurrency },
|
||||
handleSubmit
|
||||
);
|
||||
|
||||
const formErrors = getFormErrors(
|
||||
[
|
||||
"tag",
|
||||
"expiryDate",
|
||||
"expiryPeriod",
|
||||
"customer",
|
||||
"currency",
|
||||
"amount",
|
||||
"balance"
|
||||
],
|
||||
apiErrors
|
||||
);
|
||||
|
||||
const {
|
||||
tag,
|
||||
expiryPeriodAmount,
|
||||
expiryPeriodType,
|
||||
expiryType,
|
||||
balanceAmount,
|
||||
balanceCurrency
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<TextWithSelectField
|
||||
isError={!!formErrors?.balance}
|
||||
helperText={getGiftCardErrorMessage(formErrors?.balance, intl)}
|
||||
change={change}
|
||||
choices={mapSingleValueNodeToChoice(shop?.channelCurrencies)}
|
||||
containerClassName={classes.balanceContainer}
|
||||
textFieldProps={{
|
||||
type: "number",
|
||||
label: intl.formatMessage(messages.amountLabel),
|
||||
name: "balanceAmount",
|
||||
value: balanceAmount,
|
||||
minValue: 0
|
||||
}}
|
||||
selectFieldProps={{
|
||||
name: "balanceCurrency",
|
||||
value: balanceCurrency || initialCurrency,
|
||||
className: classes.currencySelectField
|
||||
}}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<GiftCardTagInput
|
||||
error={formErrors?.tag}
|
||||
name="tag"
|
||||
value={tag}
|
||||
change={change}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<Divider />
|
||||
<CardSpacer />
|
||||
<GiftCardCustomerSelectField
|
||||
selectedCustomer={selectedCustomer}
|
||||
setSelectedCustomer={setSelectedCustomer}
|
||||
/>
|
||||
<VerticalSpacer />
|
||||
<Label text={intl.formatMessage(messages.customerSubtitle)} />
|
||||
<CardSpacer />
|
||||
<Divider />
|
||||
<CardSpacer />
|
||||
<GiftCardExpirySelect
|
||||
errors={formErrors}
|
||||
change={change}
|
||||
expiryType={expiryType}
|
||||
expiryPeriodAmount={expiryPeriodAmount}
|
||||
expiryPeriodType={expiryPeriodType}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<TextField
|
||||
name="note"
|
||||
onChange={change}
|
||||
multiline
|
||||
className={classes.noteField}
|
||||
label={`${intl.formatMessage(
|
||||
messages.noteLabel
|
||||
)} *${intl.formatMessage(commonMessages.optionalField)}`}
|
||||
/>
|
||||
<VerticalSpacer />
|
||||
<Label text={intl.formatMessage(messages.noteSubtitle)} />
|
||||
</DialogContent>
|
||||
<DialogButtons
|
||||
onConfirm={submit}
|
||||
confirmButtonLabel={intl.formatMessage(messages.issueButtonLabel)}
|
||||
confirmButtonState={opts?.status}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardCreateDialogForm;
|
|
@ -0,0 +1,61 @@
|
|||
import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField";
|
||||
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { getFullName } from "@saleor/misc";
|
||||
import useCustomerSearch from "@saleor/searches/useCustomerSearch";
|
||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { giftCardCreateDialogMessages as messages } from "./messages";
|
||||
import { GiftCardCreateFormCustomer } from "./types";
|
||||
|
||||
export interface GiftCardCustomerSelectFieldProps {
|
||||
selectedCustomer: GiftCardCreateFormCustomer;
|
||||
setSelectedCustomer: (customer: GiftCardCreateFormCustomer) => void;
|
||||
}
|
||||
|
||||
const GiftCardCustomerSelectField: React.FC<GiftCardCustomerSelectFieldProps> = ({
|
||||
selectedCustomer,
|
||||
setSelectedCustomer
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { loadMore, search, result } = useCustomerSearch({
|
||||
variables: DEFAULT_INITIAL_SEARCH_DATA
|
||||
});
|
||||
|
||||
const customers = mapEdgesToItems(result?.data?.search);
|
||||
|
||||
const choices = customers?.map(({ email, firstName, lastName }) => ({
|
||||
value: email,
|
||||
label: getFullName({ firstName, lastName })
|
||||
}));
|
||||
|
||||
const handleSelect = (event: React.ChangeEvent<any>) => {
|
||||
const value = event.target.value;
|
||||
const label = choices?.find(category => category.value === value)?.label;
|
||||
|
||||
setSelectedCustomer({ email: value, name: label });
|
||||
};
|
||||
|
||||
const label = `${intl.formatMessage(
|
||||
messages.customerLabel
|
||||
)} *${intl.formatMessage(commonMessages.optionalField)}`;
|
||||
|
||||
return (
|
||||
<SingleAutocompleteSelectField
|
||||
name="customer"
|
||||
label={label}
|
||||
data-test-id="customer-field"
|
||||
displayValue={selectedCustomer.name}
|
||||
value={selectedCustomer.email}
|
||||
choices={choices || []}
|
||||
fetchChoices={search}
|
||||
onChange={handleSelect}
|
||||
onFetchMore={loadMore}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardCustomerSelectField;
|
2
src/giftCards/GiftCardCreateDialog/index.tsx
Normal file
2
src/giftCards/GiftCardCreateDialog/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardCreateDialog";
|
||||
export { default } from "./GiftCardCreateDialog";
|
50
src/giftCards/GiftCardCreateDialog/messages.ts
Normal file
50
src/giftCards/GiftCardCreateDialog/messages.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardCreateDialogMessages = defineMessages({
|
||||
title: {
|
||||
defaultMessage: "Issue gift card",
|
||||
description: "GiftCardCreateDialog title"
|
||||
},
|
||||
amountLabel: {
|
||||
defaultMessage: "Enter amount",
|
||||
description: "GiftCardCreateDialog amount label"
|
||||
},
|
||||
issueButtonLabel: {
|
||||
defaultMessage: "Issue",
|
||||
description: "GiftCardCreateDialog issue button label"
|
||||
},
|
||||
customerLabel: {
|
||||
defaultMessage: "Customer",
|
||||
description: "GiftCardCreateDialog customer label"
|
||||
},
|
||||
customerSubtitle: {
|
||||
defaultMessage:
|
||||
"Selected customer will be sent the generated gift card code. Someone else can redeem the gift card code. Gift card will be assigned to account which redeemed the code.",
|
||||
description: "GiftCardCreateDialog customer subtitle"
|
||||
},
|
||||
noteLabel: {
|
||||
defaultMessage: "Note",
|
||||
description: "GiftCardCreateDialog note label"
|
||||
},
|
||||
noteSubtitle: {
|
||||
defaultMessage:
|
||||
"Why was this gift card issued. This note will not be shown to the customer. Note will be stored in gift card history",
|
||||
description: "GiftCardCreateDialog note subtitle"
|
||||
},
|
||||
createdGiftCardLabel: {
|
||||
defaultMessage: "This is the code of a created gift card:",
|
||||
description: "GiftCardCreateDialog created gift card label"
|
||||
},
|
||||
copyCodeLabel: {
|
||||
defaultMessage: "Copy code",
|
||||
description: "GiftCardCreateDialog copy code label"
|
||||
},
|
||||
copiedToClipboardTitle: {
|
||||
defaultMessage: "Copied to clipboard",
|
||||
description: "GiftCardCreateDialog copied to clipboard title"
|
||||
},
|
||||
createdSuccessAlertTitle: {
|
||||
defaultMessage: "Successfully created gift card",
|
||||
description: "GiftCardCreateDialog createdSuccessAlertTitle"
|
||||
}
|
||||
});
|
26
src/giftCards/GiftCardCreateDialog/mutations.ts
Normal file
26
src/giftCards/GiftCardCreateDialog/mutations.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import makeMutation from "@saleor/hooks/makeMutation";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import {
|
||||
GiftCardCreate,
|
||||
GiftCardCreateVariables
|
||||
} from "./types/GiftCardCreate";
|
||||
|
||||
const giftCardCreate = gql`
|
||||
mutation GiftCardCreate($input: GiftCardCreateInput!) {
|
||||
giftCardCreate(input: $input) {
|
||||
giftCard {
|
||||
code
|
||||
}
|
||||
errors {
|
||||
code
|
||||
field
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useGiftCardCreateMutation = makeMutation<
|
||||
GiftCardCreate,
|
||||
GiftCardCreateVariables
|
||||
>(giftCardCreate);
|
25
src/giftCards/GiftCardCreateDialog/styles.ts
Normal file
25
src/giftCards/GiftCardCreateDialog/styles.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
|
||||
export const useGiftCardCreateDialogCodeContentStyles = makeStyles(
|
||||
() => ({
|
||||
buttonsContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
minWidth: 450
|
||||
}
|
||||
}),
|
||||
{ name: "GiftCardCreateDialogCodeContent" }
|
||||
);
|
||||
|
||||
export const useGiftCardCreateDialogFormStyles = makeStyles(
|
||||
() => ({
|
||||
noteField: {
|
||||
width: "100%"
|
||||
},
|
||||
currencySelectField: {
|
||||
width: 100
|
||||
},
|
||||
balanceContainer: { width: "100%" }
|
||||
}),
|
||||
{ name: "GiftCardCreateDialogForm" }
|
||||
);
|
32
src/giftCards/GiftCardCreateDialog/types.ts
Normal file
32
src/giftCards/GiftCardCreateDialog/types.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { GiftCardError } from "@saleor/fragments/types/GiftCardError";
|
||||
import { FormChange } from "@saleor/hooks/useForm";
|
||||
import {
|
||||
GiftCardExpiryTypeEnum,
|
||||
TimePeriodTypeEnum
|
||||
} from "@saleor/types/globalTypes";
|
||||
|
||||
export interface GiftCardCreateFormCustomer {
|
||||
name: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface GiftCardCommonFormData {
|
||||
tag: string;
|
||||
balanceAmount: number;
|
||||
balanceCurrency: string;
|
||||
expiryDate: string;
|
||||
expiryType: GiftCardExpiryTypeEnum;
|
||||
expiryPeriodType: TimePeriodTypeEnum;
|
||||
expiryPeriodAmount: number;
|
||||
}
|
||||
|
||||
export type GiftCardCreateFormErrors = Record<
|
||||
"tag" | "expiryDate" | "expiryPeriod" | "customer" | "currency" | "amount",
|
||||
GiftCardError
|
||||
>;
|
||||
|
||||
export interface GiftCardCreateFormCommonProps {
|
||||
change: FormChange;
|
||||
errors: GiftCardCreateFormErrors;
|
||||
data: GiftCardCommonFormData;
|
||||
}
|
35
src/giftCards/GiftCardCreateDialog/types/GiftCardCreate.ts
Normal file
35
src/giftCards/GiftCardCreateDialog/types/GiftCardCreate.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardCreateInput, GiftCardErrorCode } from "./../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: GiftCardCreate
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardCreate_giftCardCreate_giftCard {
|
||||
__typename: "GiftCard";
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface GiftCardCreate_giftCardCreate_errors {
|
||||
__typename: "GiftCardError";
|
||||
code: GiftCardErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardCreate_giftCardCreate {
|
||||
__typename: "GiftCardCreate";
|
||||
giftCard: GiftCardCreate_giftCardCreate_giftCard | null;
|
||||
errors: GiftCardCreate_giftCardCreate_errors[];
|
||||
}
|
||||
|
||||
export interface GiftCardCreate {
|
||||
giftCardCreate: GiftCardCreate_giftCardCreate | null;
|
||||
}
|
||||
|
||||
export interface GiftCardCreateVariables {
|
||||
input: GiftCardCreateInput;
|
||||
}
|
41
src/giftCards/GiftCardCreateDialog/utils.ts
Normal file
41
src/giftCards/GiftCardCreateDialog/utils.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import {
|
||||
GiftCardExpirySettingsInput,
|
||||
GiftCardExpiryTypeEnum
|
||||
} from "@saleor/types/globalTypes";
|
||||
|
||||
import { GiftCardCommonFormData } from "./types";
|
||||
|
||||
export const getGiftCardExpirySettingsInputData = ({
|
||||
expiryType,
|
||||
expiryDate,
|
||||
expiryPeriodAmount,
|
||||
expiryPeriodType
|
||||
}: Pick<
|
||||
GiftCardCommonFormData,
|
||||
"expiryDate" | "expiryPeriodAmount" | "expiryPeriodType" | "expiryType"
|
||||
>): GiftCardExpirySettingsInput => {
|
||||
switch (expiryType) {
|
||||
case GiftCardExpiryTypeEnum.EXPIRY_DATE: {
|
||||
return {
|
||||
expiryType,
|
||||
expiryDate
|
||||
};
|
||||
}
|
||||
|
||||
case GiftCardExpiryTypeEnum.EXPIRY_PERIOD: {
|
||||
return {
|
||||
expiryType,
|
||||
expiryPeriod: {
|
||||
amount: expiryPeriodAmount,
|
||||
type: expiryPeriodType
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return {
|
||||
expiryType
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
24
src/giftCards/GiftCardUpdate/GiftCardUpdate.tsx
Normal file
24
src/giftCards/GiftCardUpdate/GiftCardUpdate.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import React from "react";
|
||||
|
||||
import GiftCardUpdatePage from "./GiftCardUpdatePage";
|
||||
import GiftCardDetailsProvider from "./providers/GiftCardDetailsProvider";
|
||||
import GiftCardUpdateDialogsProvider from "./providers/GiftCardUpdateDialogsProvider";
|
||||
import GiftCardUpdateFormProvider from "./providers/GiftCardUpdateFormProvider/GiftCardUpdateFormProvider";
|
||||
import { GiftCardUpdatePageUrlQueryParams } from "./types";
|
||||
|
||||
interface GiftCardUpdateProps {
|
||||
params: GiftCardUpdatePageUrlQueryParams;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const GiftCardUpdate: React.FC<GiftCardUpdateProps> = ({ id, params }) => (
|
||||
<GiftCardDetailsProvider id={id}>
|
||||
<GiftCardUpdateFormProvider>
|
||||
<GiftCardUpdateDialogsProvider id={id} params={params}>
|
||||
<GiftCardUpdatePage />
|
||||
</GiftCardUpdateDialogsProvider>
|
||||
</GiftCardUpdateFormProvider>
|
||||
</GiftCardDetailsProvider>
|
||||
);
|
||||
|
||||
export default GiftCardUpdate;
|
|
@ -0,0 +1,137 @@
|
|||
import { TextField, Typography } from "@material-ui/core";
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Form from "@saleor/components/Form";
|
||||
import { IMessage } from "@saleor/components/messages";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import commonErrorMessages from "@saleor/utils/errors/common";
|
||||
import { DialogActionHandlers } from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { giftCardsListTableMessages as tableMessages } from "../../GiftCardsList/messages";
|
||||
import { getGiftCardErrorMessage } from "../messages";
|
||||
import { useGiftCardUpdateMutation } from "../mutations";
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import { GiftCardUpdate } from "../types/GiftCardUpdate";
|
||||
import { giftCardUpdateBalanceDialogMessages as messages } from "./messages";
|
||||
import { useUpdateBalanceDialogStyles as useStyles } from "./styles";
|
||||
|
||||
export interface GiftCardBalanceUpdateFormData {
|
||||
balanceAmount: number;
|
||||
}
|
||||
|
||||
const GiftCardUpdateBalanceDialog: React.FC<DialogActionHandlers> = ({
|
||||
open,
|
||||
onClose
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
const notify = useNotifier();
|
||||
|
||||
const {
|
||||
giftCard: {
|
||||
id,
|
||||
currentBalance: { amount, currency }
|
||||
}
|
||||
} = useGiftCardDetails();
|
||||
|
||||
const initialFormData: GiftCardBalanceUpdateFormData = {
|
||||
balanceAmount: amount
|
||||
};
|
||||
|
||||
const onCompleted = (data: GiftCardUpdate) => {
|
||||
const errors = data?.giftCardUpdate?.errors;
|
||||
|
||||
const notifierData: IMessage = !!errors?.length
|
||||
? {
|
||||
status: "error",
|
||||
text: intl.formatMessage(commonErrorMessages.unknownError)
|
||||
}
|
||||
: {
|
||||
status: "success",
|
||||
text: intl.formatMessage(messages.updatedSuccessAlertTitle)
|
||||
};
|
||||
|
||||
notify(notifierData);
|
||||
|
||||
if (!errors.length) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const [
|
||||
updateGiftCardBalance,
|
||||
updateGiftCardBalanceOpts
|
||||
] = useGiftCardUpdateMutation({
|
||||
onCompleted
|
||||
});
|
||||
|
||||
const handleSubmit = async ({
|
||||
balanceAmount
|
||||
}: GiftCardBalanceUpdateFormData) => {
|
||||
const result = await updateGiftCardBalance({
|
||||
variables: {
|
||||
id,
|
||||
input: {
|
||||
balanceAmount
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result?.data?.giftCardUpdate?.errors;
|
||||
};
|
||||
|
||||
const { loading, status, data } = updateGiftCardBalanceOpts;
|
||||
|
||||
const formErrors = getFormErrors(
|
||||
["initialBalanceAmount"],
|
||||
data?.giftCardUpdate?.errors
|
||||
);
|
||||
|
||||
return (
|
||||
<Form initial={initialFormData} onSubmit={handleSubmit}>
|
||||
{({ data, change, submit, hasChanged }) => (
|
||||
<ActionDialog
|
||||
maxWidth="sm"
|
||||
open={open}
|
||||
onConfirm={submit}
|
||||
confirmButtonLabel={intl.formatMessage(messages.changeButtonLabel)}
|
||||
onClose={onClose}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
confirmButtonState={status}
|
||||
disabled={loading || !hasChanged}
|
||||
>
|
||||
<Typography>{intl.formatMessage(messages.subtitle)}</Typography>
|
||||
<CardSpacer />
|
||||
<TextField
|
||||
inputProps={{ min: 0 }}
|
||||
error={!!formErrors?.initialBalanceAmount}
|
||||
helperText={getGiftCardErrorMessage(
|
||||
formErrors?.initialBalanceAmount,
|
||||
intl
|
||||
)}
|
||||
name="balanceAmount"
|
||||
value={data.balanceAmount}
|
||||
onChange={change}
|
||||
className={classes.inputContainer}
|
||||
label={intl.formatMessage(
|
||||
tableMessages.giftCardsTableColumnBalanceTitle
|
||||
)}
|
||||
type="number"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<div className={classes.currencyCodeContainer}>
|
||||
<Typography variant="caption">{currency}</Typography>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ActionDialog>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateBalanceDialog;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdateBalanceDialog";
|
||||
export { default } from "./GiftCardUpdateBalanceDialog";
|
|
@ -0,0 +1,22 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardUpdateBalanceDialogMessages = defineMessages({
|
||||
title: {
|
||||
defaultMessage: "Set balance",
|
||||
description: "GiftCardUpdateDetailsCard set balance button label"
|
||||
},
|
||||
subtitle: {
|
||||
defaultMessage:
|
||||
"What would you like to set cards balance to. When you change the balance both values will be changed",
|
||||
description: "GiftCardUpdateDetailsCard set balance dialog subtitle"
|
||||
},
|
||||
updatedSuccessAlertTitle: {
|
||||
defaultMessage: "Successfully updated card balance",
|
||||
description: "GiftCardUpdateDetailsCard update success alert title"
|
||||
},
|
||||
changeButtonLabel: {
|
||||
defaultMessage: "Change",
|
||||
description:
|
||||
"GiftCardUpdateDetailsCard set balance dialog change button label"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
|
||||
export const useUpdateBalanceDialogStyles = makeStyles(
|
||||
theme => ({
|
||||
inputContainer: {
|
||||
width: "100%"
|
||||
},
|
||||
currencyCodeContainer: {
|
||||
height: 35,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "flex-end",
|
||||
marginRight: theme.spacing(1)
|
||||
}
|
||||
}),
|
||||
{ name: "GiftCardUpdateBalanceDialog" }
|
||||
);
|
|
@ -0,0 +1,50 @@
|
|||
import { Typography } from "@material-ui/core";
|
||||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Money from "@saleor/components/Money";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import { giftCardUpdateDetailsCardMessages as messages } from "./messages";
|
||||
import { useGiftCardDetailsBalanceStyles as useStyles } from "./styles";
|
||||
|
||||
const GiftCardUpdateDetailsBalanceSection: React.FC = () => {
|
||||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
giftCard: { currentBalance, initialBalance }
|
||||
} = useGiftCardDetails();
|
||||
|
||||
const progressBarWidth = !!currentBalance.amount
|
||||
? Math.floor((currentBalance.amount / initialBalance.amount) * 100)
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classNames(classes.labelsContainer, classes.wideContainer)}
|
||||
>
|
||||
<Typography>{intl.formatMessage(messages.cardBalanceLabel)}</Typography>
|
||||
<div className={classes.labelsContainer}>
|
||||
<Money money={currentBalance} />
|
||||
<HorizontalSpacer />
|
||||
/
|
||||
<HorizontalSpacer />
|
||||
<Money money={initialBalance} />
|
||||
</div>
|
||||
</div>
|
||||
<CardSpacer />
|
||||
<div className={classes.balanceBar}>
|
||||
<div
|
||||
style={{ width: `${progressBarWidth}%` }}
|
||||
className={classes.balanceBarProgress}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateDetailsBalanceSection;
|
|
@ -0,0 +1,74 @@
|
|||
import { Button, Card, CardContent, Divider } from "@material-ui/core";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import GiftCardExpirySelect from "@saleor/giftCards/components/GiftCardExpirySelect";
|
||||
import GiftCardTagInput from "@saleor/giftCards/components/GiftCardTagInput";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import useGiftCardUpdateDialogs from "../providers/GiftCardUpdateDialogsProvider/hooks/useGiftCardUpdateDialogs";
|
||||
import useGiftCardUpdateForm from "../providers/GiftCardUpdateFormProvider/hooks/useGiftCardUpdateForm";
|
||||
import GiftCardUpdateDetailsBalanceSection from "./GiftCardUpdateDetailsBalanceSection";
|
||||
import { giftCardUpdateDetailsCardMessages as messages } from "./messages";
|
||||
|
||||
const GiftCardUpdateDetailsCard: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { loading } = useGiftCardDetails();
|
||||
const { openSetBalanceDialog } = useGiftCardUpdateDialogs();
|
||||
|
||||
const {
|
||||
change,
|
||||
data: { expiryType, expiryPeriodAmount, expiryPeriodType, tag, expiryDate },
|
||||
formErrors
|
||||
} = useGiftCardUpdateForm();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage(messages.title)}
|
||||
toolbar={
|
||||
<Button
|
||||
data-test-id="set-balance-button"
|
||||
color="primary"
|
||||
onClick={openSetBalanceDialog}
|
||||
>
|
||||
{intl.formatMessage(messages.setBalanceButtonLabel)}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<CardContent>
|
||||
<Skeleton>
|
||||
{!loading && (
|
||||
<>
|
||||
<GiftCardUpdateDetailsBalanceSection />
|
||||
<CardSpacer />
|
||||
<Divider />
|
||||
<CardSpacer />
|
||||
<GiftCardTagInput
|
||||
error={formErrors?.tag}
|
||||
name="tag"
|
||||
withTopLabel
|
||||
value={tag}
|
||||
change={change}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<GiftCardExpirySelect
|
||||
expiryDate={expiryDate}
|
||||
errors={formErrors}
|
||||
change={change}
|
||||
expiryType={expiryType}
|
||||
expiryPeriodAmount={expiryPeriodAmount}
|
||||
expiryPeriodType={expiryPeriodType}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Skeleton>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateDetailsCard;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdateDetailsCard";
|
||||
export { default } from "./GiftCardUpdateDetailsCard";
|
|
@ -0,0 +1,16 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardUpdateDetailsCardMessages = defineMessages({
|
||||
title: {
|
||||
defaultMessage: "Details",
|
||||
description: "GiftCardUpdateDetailsCard title"
|
||||
},
|
||||
setBalanceButtonLabel: {
|
||||
defaultMessage: "set balance",
|
||||
description: "GiftCardUpdateDetailsCard set balance button label"
|
||||
},
|
||||
cardBalanceLabel: {
|
||||
defaultMessage: "Card Balance",
|
||||
description: "GiftCardUpdateDetailsCard card balance label"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,28 @@
|
|||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
|
||||
export const useGiftCardDetailsBalanceStyles = makeStyles(
|
||||
theme => ({
|
||||
labelsContainer: {
|
||||
display: "flex",
|
||||
alignItems: "baseline"
|
||||
},
|
||||
wideContainer: {
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
balanceBar: {
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
height: 36,
|
||||
padding: "0 4px",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
borderRadius: 18
|
||||
},
|
||||
balanceBarProgress: {
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
backgroundColor: theme.palette.primary.light
|
||||
}
|
||||
}),
|
||||
{ name: "GiftCardUpdateDetailsBalanceSection" }
|
||||
);
|
|
@ -0,0 +1,26 @@
|
|||
import { Card, CardContent } from "@material-ui/core";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import GiftCardUpdateInfoCardContent from "./GiftCardUpdateInfoCardContent";
|
||||
import { giftCardUpdateInfoCardMessages as messages } from "./messages";
|
||||
|
||||
const GiftCardUpdateInfoCard: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { loading } = useGiftCardDetails();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={intl.formatMessage(messages.title)} />
|
||||
<CardContent>
|
||||
<Skeleton>{!loading && <GiftCardUpdateInfoCardContent />}</Skeleton>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateInfoCard;
|
|
@ -0,0 +1,143 @@
|
|||
import { Typography } from "@material-ui/core";
|
||||
import { appUrl } from "@saleor/apps/urls";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Link from "@saleor/components/Link";
|
||||
import { customerUrl } from "@saleor/customers/urls";
|
||||
import useDateLocalize from "@saleor/hooks/useDateLocalize";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import { getFullName, getStringOrPlaceholder } from "@saleor/misc";
|
||||
import Label from "@saleor/orders/components/OrderHistory/Label";
|
||||
import { getOrderNumberLinkObject } from "@saleor/orders/components/OrderHistory/utils";
|
||||
import { productUrl } from "@saleor/products/urls";
|
||||
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
||||
import { GiftCardEventsEnum } from "@saleor/types/globalTypes";
|
||||
import React from "react";
|
||||
import { MessageDescriptor, useIntl } from "react-intl";
|
||||
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import { giftCardUpdateInfoCardMessages as messages } from "./messages";
|
||||
|
||||
const PLACEHOLDER = "-";
|
||||
|
||||
const GiftCardUpdateInfoCardContent: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const localizeDate = useDateLocalize();
|
||||
const navigate = useNavigator();
|
||||
|
||||
const { giftCard } = useGiftCardDetails();
|
||||
|
||||
const {
|
||||
created,
|
||||
createdByEmail,
|
||||
createdBy,
|
||||
usedByEmail,
|
||||
usedBy,
|
||||
app,
|
||||
product,
|
||||
events
|
||||
} = giftCard;
|
||||
|
||||
const cardIssuedEvent = events.find(
|
||||
({ type }) => type === GiftCardEventsEnum.ISSUED
|
||||
);
|
||||
|
||||
const getBuyerFieldData = (): {
|
||||
label: MessageDescriptor;
|
||||
name: string;
|
||||
url?: string;
|
||||
} => {
|
||||
// createdBy can be either customer or staff hence
|
||||
// we check for issued event
|
||||
if (cardIssuedEvent) {
|
||||
const userName = getFullName(createdBy);
|
||||
|
||||
return {
|
||||
label: messages.issuedByLabel,
|
||||
name: userName || createdByEmail,
|
||||
url: staffMemberDetailsUrl(createdBy.id)
|
||||
};
|
||||
}
|
||||
|
||||
if (createdByEmail) {
|
||||
return {
|
||||
label: messages.boughtByLabel,
|
||||
name: createdByEmail
|
||||
};
|
||||
}
|
||||
|
||||
if (app) {
|
||||
return {
|
||||
label: messages.issuedByAppLabel,
|
||||
name: app.name,
|
||||
url: appUrl(app.id)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
label: messages.boughtByLabel,
|
||||
name: getFullName(createdBy),
|
||||
url: customerUrl(createdBy?.id)
|
||||
};
|
||||
};
|
||||
|
||||
const orderData =
|
||||
cardIssuedEvent && cardIssuedEvent.orderId
|
||||
? getOrderNumberLinkObject({
|
||||
id: cardIssuedEvent.orderId,
|
||||
number: cardIssuedEvent.orderNumber
|
||||
})
|
||||
: null;
|
||||
|
||||
const {
|
||||
label: buyerLabelMessage,
|
||||
name: buyerName,
|
||||
url: buyerUrl
|
||||
} = getBuyerFieldData();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Label text={intl.formatMessage(messages.creationLabel)} />
|
||||
<Typography>{localizeDate(created, "DD MMMM YYYY")}</Typography>
|
||||
<CardSpacer />
|
||||
|
||||
<Label text={intl.formatMessage(messages.orderNumberLabel)} />
|
||||
{orderData ? (
|
||||
<Link onClick={() => navigate(orderData.link)}>{orderData.text}</Link>
|
||||
) : (
|
||||
<Typography>{PLACEHOLDER}</Typography>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
||||
<Label text={intl.formatMessage(messages.productLabel)} />
|
||||
{product ? (
|
||||
<Link onClick={() => navigate(productUrl(product?.id))}>
|
||||
{product?.name}
|
||||
</Link>
|
||||
) : (
|
||||
<Typography>{PLACEHOLDER}</Typography>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
||||
<Label text={intl.formatMessage(buyerLabelMessage)} />
|
||||
{buyerUrl ? (
|
||||
<Link onClick={() => navigate(buyerUrl)}>{buyerName}</Link>
|
||||
) : (
|
||||
<Typography>{buyerName}</Typography>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
||||
<Label text={intl.formatMessage(messages.usedByLabel)} />
|
||||
{usedBy ? (
|
||||
<Link onClick={() => navigate(customerUrl(usedBy.id))}>
|
||||
{getFullName(usedBy)}
|
||||
</Link>
|
||||
) : (
|
||||
<Typography>
|
||||
{getStringOrPlaceholder(usedByEmail, PLACEHOLDER)}
|
||||
</Typography>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateInfoCardContent;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdateInfoCard";
|
||||
export { default } from "./GiftCardUpdateInfoCard";
|
|
@ -0,0 +1,36 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardUpdateInfoCardMessages = defineMessages({
|
||||
title: {
|
||||
defaultMessage: "Card information",
|
||||
description: "GiftCardUpdateInfoCard title"
|
||||
},
|
||||
creationLabel: {
|
||||
defaultMessage: "Creation",
|
||||
description: "GiftCardUpdateInfoCard creation label"
|
||||
},
|
||||
orderNumberLabel: {
|
||||
defaultMessage: "Order number",
|
||||
description: "GiftCardUpdateInfoCard order number label"
|
||||
},
|
||||
productLabel: {
|
||||
defaultMessage: "Product bought to get gift card",
|
||||
description: "GiftCardUpdateInfoCard product label"
|
||||
},
|
||||
issuedByLabel: {
|
||||
defaultMessage: "Issued by",
|
||||
description: "GiftCardUpdateInfoCard issued by label"
|
||||
},
|
||||
issuedByAppLabel: {
|
||||
defaultMessage: "Issued by app",
|
||||
description: "GiftCardUpdateInfoCard issued by app label"
|
||||
},
|
||||
boughtByLabel: {
|
||||
defaultMessage: "Bought by",
|
||||
description: "GiftCardUpdateInfoCard bought by label"
|
||||
},
|
||||
usedByLabel: {
|
||||
defaultMessage: "Used by",
|
||||
description: "GiftCardUpdateInfoCard used by label"
|
||||
}
|
||||
});
|
52
src/giftCards/GiftCardUpdate/GiftCardUpdatePage.tsx
Normal file
52
src/giftCards/GiftCardUpdate/GiftCardUpdatePage.tsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Container from "@saleor/components/Container";
|
||||
import Grid from "@saleor/components/Grid";
|
||||
import Metadata from "@saleor/components/Metadata";
|
||||
import Savebar from "@saleor/components/Savebar";
|
||||
import React from "react";
|
||||
|
||||
import GiftCardUpdateDetailsCard from "./GiftCardUpdateDetailsCard";
|
||||
import GiftCardUpdateInfoCard from "./GiftCardUpdateInfoCard";
|
||||
import GiftCardUpdatePageHeader from "./GiftCardUpdatePageHeader";
|
||||
import useGiftCardUpdateDialogs from "./providers/GiftCardUpdateDialogsProvider/hooks/useGiftCardUpdateDialogs";
|
||||
import useGiftCardUpdate from "./providers/GiftCardUpdateFormProvider/hooks/useGiftCardUpdate";
|
||||
import useGiftCardUpdateForm from "./providers/GiftCardUpdateFormProvider/hooks/useGiftCardUpdateForm";
|
||||
|
||||
const GiftCardUpdatePage: React.FC = () => {
|
||||
const { navigateBack } = useGiftCardUpdateDialogs();
|
||||
|
||||
const {
|
||||
hasChanged,
|
||||
submit,
|
||||
data,
|
||||
handlers: { changeMetadata }
|
||||
} = useGiftCardUpdateForm();
|
||||
|
||||
const {
|
||||
opts: { loading: loadingUpdate, status }
|
||||
} = useGiftCardUpdate();
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<GiftCardUpdatePageHeader />
|
||||
<Grid>
|
||||
<div>
|
||||
<GiftCardUpdateDetailsCard />
|
||||
<CardSpacer />
|
||||
<Metadata data={data} onChange={changeMetadata} />
|
||||
</div>
|
||||
<div>
|
||||
<GiftCardUpdateInfoCard />
|
||||
</div>
|
||||
</Grid>
|
||||
<Savebar
|
||||
state={status}
|
||||
disabled={loadingUpdate || !hasChanged}
|
||||
onCancel={navigateBack}
|
||||
onSubmit={submit}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdatePage;
|
|
@ -0,0 +1,105 @@
|
|||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { ConfirmButton } from "@saleor/macaw-ui";
|
||||
import commonErrorMessages from "@saleor/utils/errors/common";
|
||||
import classNames from "classnames";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import { giftCardEnableDisableSectionMessages as messages } from "./messages";
|
||||
import {
|
||||
useGiftCardActivateMutation,
|
||||
useGiftCardDeactivateMutation
|
||||
} from "./mutations";
|
||||
import { useGiftCardEnableDisableSectionStyles as useStyles } from "./styles";
|
||||
import { GiftCardActivate } from "./types/GiftCardActivate";
|
||||
import { GiftCardDeactivate } from "./types/GiftCardDeactivate";
|
||||
|
||||
const GiftCardEnableDisableSection: React.FC = () => {
|
||||
const classes = useStyles({});
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
giftCard: { id, isActive }
|
||||
} = useGiftCardDetails();
|
||||
|
||||
const [showButtonGreen, setShowButtonGreen] = useState(!isActive);
|
||||
|
||||
useEffect(() => setShowButtonGreen(!isActive), [isActive]);
|
||||
|
||||
const onActivateCompleted = (data: GiftCardActivate) => {
|
||||
const errors = data?.giftCardActivate?.errors;
|
||||
|
||||
if (!!errors?.length) {
|
||||
notify({
|
||||
status: "error",
|
||||
text: intl.formatMessage(commonErrorMessages.unknownError)
|
||||
});
|
||||
|
||||
setShowButtonGreen(false);
|
||||
setTimeout(() => setShowButtonGreen(true), 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage(messages.successfullyEnabledTitle)
|
||||
});
|
||||
};
|
||||
|
||||
const onDeactivateCompleted = (data: GiftCardDeactivate) => {
|
||||
const errors = data?.giftCardDeactivate?.errors;
|
||||
|
||||
if (!!errors?.length) {
|
||||
notify({
|
||||
status: "error",
|
||||
text: intl.formatMessage(commonErrorMessages.unknownError)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage(messages.successfullyDisabledTitle)
|
||||
});
|
||||
};
|
||||
|
||||
const [giftCardActivate, giftCardActivateOpts] = useGiftCardActivateMutation({
|
||||
onCompleted: onActivateCompleted
|
||||
});
|
||||
|
||||
const [
|
||||
giftCardDeactivate,
|
||||
giftCardDeactivateOpts
|
||||
] = useGiftCardDeactivateMutation({
|
||||
onCompleted: onDeactivateCompleted
|
||||
});
|
||||
|
||||
const handleClick = () =>
|
||||
isActive
|
||||
? giftCardDeactivate({ variables: { id } })
|
||||
: giftCardActivate({ variables: { id } });
|
||||
|
||||
const buttonLabel = isActive ? messages.disableLabel : messages.enableLabel;
|
||||
|
||||
const currentOpts = isActive ? giftCardDeactivateOpts : giftCardActivateOpts;
|
||||
|
||||
return (
|
||||
<ConfirmButton
|
||||
className={classNames(classes.button, {
|
||||
[classes.buttonRed]: isActive || currentOpts?.status === "error",
|
||||
[classes.buttonGreen]: showButtonGreen
|
||||
})}
|
||||
onClick={handleClick}
|
||||
transitionState={currentOpts?.status}
|
||||
labels={{
|
||||
confirm: intl.formatMessage(buttonLabel),
|
||||
error: intl.formatMessage(commonMessages.error)
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardEnableDisableSection;
|
|
@ -0,0 +1,56 @@
|
|||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import PageTitleWithStatusChip from "@saleor/components/PageTitleWithStatusChip";
|
||||
import { StatusType } from "@saleor/components/StatusChip/types";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { Backlink } from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { giftCardsListTableMessages as tableMessages } from "../../GiftCardsList/messages";
|
||||
import useGiftCardDetails from "../providers/GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
import useGiftCardUpdateDialogs from "../providers/GiftCardUpdateDialogsProvider/hooks/useGiftCardUpdateDialogs";
|
||||
import GiftCardEnableDisableSection from "./GiftCardEnableDisableSection";
|
||||
|
||||
const GiftCardUpdatePageHeader: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const { giftCard } = useGiftCardDetails();
|
||||
const { navigateBack } = useGiftCardUpdateDialogs();
|
||||
|
||||
if (!giftCard) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { displayCode, isActive } = giftCard;
|
||||
|
||||
const title = intl.formatMessage(tableMessages.codeEndingWithLabel, {
|
||||
displayCode
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Backlink onClick={navigateBack}>
|
||||
{intl.formatMessage(sectionNames.giftCards)}
|
||||
</Backlink>
|
||||
<PageHeader
|
||||
inline
|
||||
title={
|
||||
isActive ? (
|
||||
title
|
||||
) : (
|
||||
<PageTitleWithStatusChip
|
||||
title={title}
|
||||
statusLabel={intl.formatMessage(
|
||||
tableMessages.giftCardDisabledLabel
|
||||
)}
|
||||
statusType={StatusType.ERROR}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<GiftCardEnableDisableSection />
|
||||
</PageHeader>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdatePageHeader;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdatePageHeader";
|
||||
export { default } from "./GiftCardUpdatePageHeader";
|
|
@ -0,0 +1,20 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardEnableDisableSectionMessages = defineMessages({
|
||||
enableLabel: {
|
||||
defaultMessage: "Enable",
|
||||
description: "GiftCardEnableDisableSection enable label"
|
||||
},
|
||||
disableLabel: {
|
||||
defaultMessage: "Disable",
|
||||
description: "GiftCardEnableDisableSection enable label"
|
||||
},
|
||||
successfullyEnabledTitle: {
|
||||
defaultMessage: "Successfully enabled gift card",
|
||||
description: "GiftCardEnableDisableSection enable success"
|
||||
},
|
||||
successfullyDisabledTitle: {
|
||||
defaultMessage: "Successfully disabled gift card",
|
||||
description: "GiftCardEnableDisableSection disable success"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,53 @@
|
|||
import { giftCardErrorFragment } from "@saleor/fragments/errors";
|
||||
import makeMutation from "@saleor/hooks/makeMutation";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { giftCardDataFragment } from "../queries";
|
||||
import {
|
||||
GiftCardActivate,
|
||||
GiftCardActivateVariables
|
||||
} from "./types/GiftCardActivate";
|
||||
import {
|
||||
GiftCardDeactivate,
|
||||
GiftCardDeactivateVariables
|
||||
} from "./types/GiftCardDeactivate";
|
||||
|
||||
const giftCardActivate = gql`
|
||||
${giftCardDataFragment}
|
||||
${giftCardErrorFragment}
|
||||
mutation GiftCardActivate($id: ID!) {
|
||||
giftCardActivate(id: $id) {
|
||||
errors {
|
||||
...GiftCardError
|
||||
}
|
||||
giftCard {
|
||||
...GiftCardData
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useGiftCardActivateMutation = makeMutation<
|
||||
GiftCardActivate,
|
||||
GiftCardActivateVariables
|
||||
>(giftCardActivate);
|
||||
|
||||
const giftCardDeactivate = gql`
|
||||
${giftCardDataFragment}
|
||||
${giftCardErrorFragment}
|
||||
mutation GiftCardDeactivate($id: ID!) {
|
||||
giftCardDeactivate(id: $id) {
|
||||
errors {
|
||||
...GiftCardError
|
||||
}
|
||||
giftCard {
|
||||
...GiftCardData
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useGiftCardDeactivateMutation = makeMutation<
|
||||
GiftCardDeactivate,
|
||||
GiftCardDeactivateVariables
|
||||
>(giftCardDeactivate);
|
|
@ -0,0 +1,27 @@
|
|||
import { darken } from "@material-ui/core";
|
||||
import { statusChipStyles } from "@saleor/components/StatusChip/StatusChip";
|
||||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
|
||||
export const useGiftCardEnableDisableSectionStyles = makeStyles(
|
||||
theme => ({
|
||||
button: {
|
||||
transition: "backgroundColor 0ms"
|
||||
},
|
||||
buttonRed: {
|
||||
backgroundColor: theme.palette.error.main,
|
||||
color: "#ffffff",
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: darken(theme.palette.error.main, 0.1)
|
||||
}
|
||||
},
|
||||
buttonGreen: {
|
||||
backgroundColor: statusChipStyles.successLabel.color,
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: darken(statusChipStyles.successLabel.color, 0.1)
|
||||
}
|
||||
}
|
||||
}),
|
||||
{ name: "GiftCardEnableDisableSection" }
|
||||
);
|
|
@ -0,0 +1,117 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardErrorCode, GiftCardExpiryTypeEnum, TimePeriodTypeEnum } from "./../../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: GiftCardActivate
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_errors {
|
||||
__typename: "GiftCardError";
|
||||
code: GiftCardErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_createdBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_product {
|
||||
__typename: "Product";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_user {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_usedBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_expiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_initialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard_currentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate_giftCard {
|
||||
__typename: "GiftCard";
|
||||
metadata: (GiftCardActivate_giftCardActivate_giftCard_metadata | null)[];
|
||||
privateMetadata: (GiftCardActivate_giftCardActivate_giftCard_privateMetadata | null)[];
|
||||
displayCode: string;
|
||||
createdBy: GiftCardActivate_giftCardActivate_giftCard_createdBy | null;
|
||||
product: GiftCardActivate_giftCardActivate_giftCard_product | null;
|
||||
user: GiftCardActivate_giftCardActivate_giftCard_user | null;
|
||||
usedBy: GiftCardActivate_giftCardActivate_giftCard_usedBy | null;
|
||||
usedByEmail: string | null;
|
||||
createdByEmail: string | null;
|
||||
app: GiftCardActivate_giftCardActivate_giftCard_app | null;
|
||||
created: any;
|
||||
expiryDate: any | null;
|
||||
expiryType: GiftCardExpiryTypeEnum;
|
||||
expiryPeriod: GiftCardActivate_giftCardActivate_giftCard_expiryPeriod | null;
|
||||
lastUsedOn: any | null;
|
||||
isActive: boolean;
|
||||
initialBalance: GiftCardActivate_giftCardActivate_giftCard_initialBalance | null;
|
||||
currentBalance: GiftCardActivate_giftCardActivate_giftCard_currentBalance | null;
|
||||
id: string;
|
||||
tag: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate_giftCardActivate {
|
||||
__typename: "GiftCardActivate";
|
||||
errors: GiftCardActivate_giftCardActivate_errors[];
|
||||
giftCard: GiftCardActivate_giftCardActivate_giftCard | null;
|
||||
}
|
||||
|
||||
export interface GiftCardActivate {
|
||||
giftCardActivate: GiftCardActivate_giftCardActivate | null;
|
||||
}
|
||||
|
||||
export interface GiftCardActivateVariables {
|
||||
id: string;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardErrorCode, GiftCardExpiryTypeEnum, TimePeriodTypeEnum } from "./../../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: GiftCardDeactivate
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_errors {
|
||||
__typename: "GiftCardError";
|
||||
code: GiftCardErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_createdBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_product {
|
||||
__typename: "Product";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_user {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_usedBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_expiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_initialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard_currentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate_giftCard {
|
||||
__typename: "GiftCard";
|
||||
metadata: (GiftCardDeactivate_giftCardDeactivate_giftCard_metadata | null)[];
|
||||
privateMetadata: (GiftCardDeactivate_giftCardDeactivate_giftCard_privateMetadata | null)[];
|
||||
displayCode: string;
|
||||
createdBy: GiftCardDeactivate_giftCardDeactivate_giftCard_createdBy | null;
|
||||
product: GiftCardDeactivate_giftCardDeactivate_giftCard_product | null;
|
||||
user: GiftCardDeactivate_giftCardDeactivate_giftCard_user | null;
|
||||
usedBy: GiftCardDeactivate_giftCardDeactivate_giftCard_usedBy | null;
|
||||
usedByEmail: string | null;
|
||||
createdByEmail: string | null;
|
||||
app: GiftCardDeactivate_giftCardDeactivate_giftCard_app | null;
|
||||
created: any;
|
||||
expiryDate: any | null;
|
||||
expiryType: GiftCardExpiryTypeEnum;
|
||||
expiryPeriod: GiftCardDeactivate_giftCardDeactivate_giftCard_expiryPeriod | null;
|
||||
lastUsedOn: any | null;
|
||||
isActive: boolean;
|
||||
initialBalance: GiftCardDeactivate_giftCardDeactivate_giftCard_initialBalance | null;
|
||||
currentBalance: GiftCardDeactivate_giftCardDeactivate_giftCard_currentBalance | null;
|
||||
id: string;
|
||||
tag: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate_giftCardDeactivate {
|
||||
__typename: "GiftCardDeactivate";
|
||||
errors: GiftCardDeactivate_giftCardDeactivate_errors[];
|
||||
giftCard: GiftCardDeactivate_giftCardDeactivate_giftCard | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivate {
|
||||
giftCardDeactivate: GiftCardDeactivate_giftCardDeactivate | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDeactivateVariables {
|
||||
id: string;
|
||||
}
|
2
src/giftCards/GiftCardUpdate/index.tsx
Normal file
2
src/giftCards/GiftCardUpdate/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdate";
|
||||
export { default } from "./GiftCardUpdate";
|
34
src/giftCards/GiftCardUpdate/messages.ts
Normal file
34
src/giftCards/GiftCardUpdate/messages.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { commonMessages } from "@saleor/intl";
|
||||
import { GiftCardErrorCode } from "@saleor/types/globalTypes";
|
||||
import commonErrorMessages from "@saleor/utils/errors/common";
|
||||
import { defineMessages, IntlShape } from "react-intl";
|
||||
|
||||
import { GiftCardUpdate_giftCardUpdate_errors } from "./types/GiftCardUpdate";
|
||||
|
||||
export const giftCardUpdateDetailsCardMessages = defineMessages({
|
||||
title: {
|
||||
defaultMessage: "Details",
|
||||
description: "GiftCardUpdateDetailsCard title"
|
||||
}
|
||||
});
|
||||
|
||||
export function getGiftCardErrorMessage(
|
||||
error: Omit<GiftCardUpdate_giftCardUpdate_errors, "__typename"> | undefined,
|
||||
intl: IntlShape
|
||||
): string {
|
||||
if (error) {
|
||||
switch (error.code) {
|
||||
case GiftCardErrorCode.GRAPHQL_ERROR:
|
||||
return intl.formatMessage(commonErrorMessages.graphqlError);
|
||||
case GiftCardErrorCode.REQUIRED:
|
||||
return intl.formatMessage(commonMessages.requiredField);
|
||||
case GiftCardErrorCode.INVALID:
|
||||
return intl.formatMessage(commonErrorMessages.invalid);
|
||||
|
||||
default:
|
||||
return intl.formatMessage(commonErrorMessages.unknownError);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
29
src/giftCards/GiftCardUpdate/mutations.ts
Normal file
29
src/giftCards/GiftCardUpdate/mutations.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { giftCardErrorFragment } from "@saleor/fragments/errors";
|
||||
import makeMutation from "@saleor/hooks/makeMutation";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { giftCardDataFragment } from "./queries";
|
||||
import {
|
||||
GiftCardUpdate,
|
||||
GiftCardUpdateVariables
|
||||
} from "./types/GiftCardUpdate";
|
||||
|
||||
const giftCardUpdate = gql`
|
||||
${giftCardDataFragment}
|
||||
${giftCardErrorFragment}
|
||||
mutation GiftCardUpdate($id: ID!, $input: GiftCardUpdateInput!) {
|
||||
giftCardUpdate(id: $id, input: $input) {
|
||||
errors {
|
||||
...GiftCardError
|
||||
}
|
||||
giftCard {
|
||||
...GiftCardData
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useGiftCardUpdateMutation = makeMutation<
|
||||
GiftCardUpdate,
|
||||
GiftCardUpdateVariables
|
||||
>(giftCardUpdate);
|
|
@ -0,0 +1,41 @@
|
|||
import React, { createContext } from "react";
|
||||
|
||||
import { useGiftCardDetailsQuery } from "../../queries";
|
||||
import { GiftCardDetails_giftCard } from "../../types/GiftCardDetails";
|
||||
|
||||
interface GiftCardDetailsProviderProps {
|
||||
children: React.ReactNode;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetailsConsumerProps {
|
||||
giftCard: GiftCardDetails_giftCard;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const GiftCardDetailsContext = createContext<
|
||||
GiftCardDetailsConsumerProps
|
||||
>(null);
|
||||
|
||||
const GiftCardDetailsProvider: React.FC<GiftCardDetailsProviderProps> = ({
|
||||
children,
|
||||
id
|
||||
}) => {
|
||||
const { data, loading } = useGiftCardDetailsQuery({
|
||||
displayLoader: true,
|
||||
variables: { id }
|
||||
});
|
||||
|
||||
const providerValues: GiftCardDetailsConsumerProps = {
|
||||
giftCard: data?.giftCard,
|
||||
loading
|
||||
};
|
||||
|
||||
return (
|
||||
<GiftCardDetailsContext.Provider value={providerValues}>
|
||||
{children}
|
||||
</GiftCardDetailsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardDetailsProvider;
|
|
@ -0,0 +1,14 @@
|
|||
import { useContext } from "react";
|
||||
|
||||
import {
|
||||
GiftCardDetailsConsumerProps,
|
||||
GiftCardDetailsContext
|
||||
} from "../GiftCardDetailsProvider";
|
||||
|
||||
const useGiftCardDetails = (): GiftCardDetailsConsumerProps => {
|
||||
const giftCardDetailsConsumerProps = useContext(GiftCardDetailsContext);
|
||||
|
||||
return giftCardDetailsConsumerProps;
|
||||
};
|
||||
|
||||
export default useGiftCardDetails;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardDetailsProvider";
|
||||
export { default } from "./GiftCardDetailsProvider";
|
|
@ -0,0 +1,70 @@
|
|||
import { giftCardsListPath, giftCardUrl } from "@saleor/giftCards/urls";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import React, { createContext } from "react";
|
||||
|
||||
import GiftCardUpdateBalanceDialog from "../../GiftCardUpdateBalanceDialog";
|
||||
import {
|
||||
GiftCardUpdatePageActionParamsEnum,
|
||||
GiftCardUpdatePageUrlQueryParams
|
||||
} from "../../types";
|
||||
import useGiftCardDetails from "../GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
|
||||
interface GiftCardUpdateDialogsProviderProps {
|
||||
children: React.ReactNode;
|
||||
params: GiftCardUpdatePageUrlQueryParams;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdateDialogsConsumerProps {
|
||||
navigateBack: () => void;
|
||||
openSetBalanceDialog: () => void;
|
||||
closeDialog: () => void;
|
||||
}
|
||||
|
||||
export const GiftCardUpdateDialogsContext = createContext<
|
||||
GiftCardUpdateDialogsConsumerProps
|
||||
>(null);
|
||||
|
||||
const GiftCardUpdateDialogsProvider: React.FC<GiftCardUpdateDialogsProviderProps> = ({
|
||||
children,
|
||||
params,
|
||||
id
|
||||
}) => {
|
||||
const navigate = useNavigator();
|
||||
|
||||
const { loading: loadingGiftCard } = useGiftCardDetails();
|
||||
|
||||
const [openDialog, closeDialog] = createDialogActionHandlers<
|
||||
GiftCardUpdatePageActionParamsEnum,
|
||||
GiftCardUpdatePageUrlQueryParams
|
||||
>(navigate, params => giftCardUrl(id, params), params);
|
||||
|
||||
const openSetBalanceDialog = () =>
|
||||
openDialog(GiftCardUpdatePageActionParamsEnum.SET_BALANCE);
|
||||
|
||||
const isSetBalanceDialogOpen =
|
||||
params?.action === GiftCardUpdatePageActionParamsEnum.SET_BALANCE;
|
||||
|
||||
const navigateBack = () => navigate(giftCardsListPath);
|
||||
|
||||
const providerValues: GiftCardUpdateDialogsConsumerProps = {
|
||||
openSetBalanceDialog,
|
||||
closeDialog,
|
||||
navigateBack
|
||||
};
|
||||
|
||||
return (
|
||||
<GiftCardUpdateDialogsContext.Provider value={providerValues}>
|
||||
{children}
|
||||
{!loadingGiftCard && (
|
||||
<GiftCardUpdateBalanceDialog
|
||||
onClose={closeDialog}
|
||||
open={isSetBalanceDialogOpen}
|
||||
/>
|
||||
)}
|
||||
</GiftCardUpdateDialogsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateDialogsProvider;
|
|
@ -0,0 +1,14 @@
|
|||
import { useContext } from "react";
|
||||
|
||||
import {
|
||||
GiftCardUpdateDialogsConsumerProps,
|
||||
GiftCardUpdateDialogsContext
|
||||
} from "../GiftCardUpdateDialogsProvider";
|
||||
|
||||
const useGiftCardUpdateDialogs = (): GiftCardUpdateDialogsConsumerProps => {
|
||||
const giftCardUpdateDialogsProps = useContext(GiftCardUpdateDialogsContext);
|
||||
|
||||
return giftCardUpdateDialogsProps;
|
||||
};
|
||||
|
||||
export default useGiftCardUpdateDialogs;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdateDialogsProvider";
|
||||
export { default } from "./GiftCardUpdateDialogsProvider";
|
|
@ -0,0 +1,163 @@
|
|||
import { MetadataFormData } from "@saleor/components/Metadata";
|
||||
import { GiftCardError } from "@saleor/fragments/types/GiftCardError";
|
||||
import { GiftCardCommonFormData } from "@saleor/giftCards/GiftCardCreateDialog/types";
|
||||
import { getGiftCardExpirySettingsInputData } from "@saleor/giftCards/GiftCardCreateDialog/utils";
|
||||
import { MutationResultWithOpts } from "@saleor/hooks/makeMutation";
|
||||
import useForm, { FormChange, UseFormResult } from "@saleor/hooks/useForm";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import { getDefaultNotifierSuccessErrorData } from "@saleor/hooks/useNotifier/utils";
|
||||
import { TimePeriodTypeEnum } from "@saleor/types/globalTypes";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
|
||||
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
|
||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||
import getMetadata from "@saleor/utils/metadata/getMetadata";
|
||||
import {
|
||||
useMetadataUpdate,
|
||||
usePrivateMetadataUpdate
|
||||
} from "@saleor/utils/metadata/updateMetadata";
|
||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||
import React, { createContext } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { initialData as emptyFormData } from "../../../GiftCardCreateDialog/GiftCardCreateDialogForm";
|
||||
import { useGiftCardUpdateMutation } from "../../mutations";
|
||||
import { GiftCardUpdate } from "../../types/GiftCardUpdate";
|
||||
import useGiftCardDetails from "../GiftCardDetailsProvider/hooks/useGiftCardDetails";
|
||||
|
||||
interface GiftCardUpdateFormProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export type GiftCardUpdateFormData = MetadataFormData &
|
||||
Omit<GiftCardCommonFormData, "balanceAmount" | "balanceCurrency">;
|
||||
|
||||
export interface GiftCardUpdateFormConsumerData
|
||||
extends GiftCardUpdateFormErrors {
|
||||
opts: MutationResultWithOpts<GiftCardUpdate>;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdateFormErrors {
|
||||
formErrors: Record<"tag" | "expiryDate" | "expiryPeriod", GiftCardError>;
|
||||
handlers: { changeMetadata: FormChange };
|
||||
}
|
||||
|
||||
export type GiftCardUpdateFormConsumerProps = UseFormResult<
|
||||
GiftCardUpdateFormData
|
||||
> &
|
||||
GiftCardUpdateFormConsumerData;
|
||||
|
||||
export const GiftCardUpdateFormContext = createContext<
|
||||
GiftCardUpdateFormConsumerProps
|
||||
>(null);
|
||||
|
||||
const GiftCardUpdateFormProvider: React.FC<GiftCardUpdateFormProviderProps> = ({
|
||||
children
|
||||
}) => {
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
const [updateMetadata] = useMetadataUpdate({});
|
||||
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
|
||||
|
||||
const { loading: loadingGiftCard, giftCard } = useGiftCardDetails();
|
||||
|
||||
const getInitialData = (): GiftCardUpdateFormData => {
|
||||
if (loadingGiftCard || !giftCard) {
|
||||
return { ...emptyFormData, metadata: [], privateMetadata: [] };
|
||||
}
|
||||
|
||||
const {
|
||||
tag,
|
||||
expiryDate,
|
||||
expiryType,
|
||||
expiryPeriod,
|
||||
privateMetadata,
|
||||
metadata
|
||||
} = giftCard;
|
||||
|
||||
return {
|
||||
tag,
|
||||
expiryDate,
|
||||
expiryType,
|
||||
expiryPeriodType: expiryPeriod?.type || TimePeriodTypeEnum.YEAR,
|
||||
expiryPeriodAmount: expiryPeriod?.amount || 1,
|
||||
privateMetadata: privateMetadata?.map(mapMetadataItemToInput),
|
||||
metadata: metadata?.map(mapMetadataItemToInput)
|
||||
};
|
||||
};
|
||||
|
||||
const onSubmit = (data: GiftCardUpdate) => {
|
||||
const errors = data.giftCardUpdate.errors;
|
||||
|
||||
notify(getDefaultNotifierSuccessErrorData(errors, intl));
|
||||
};
|
||||
|
||||
const [updateGiftCard, updateGiftCardOpts] = useGiftCardUpdateMutation({
|
||||
onCompleted: onSubmit
|
||||
});
|
||||
|
||||
const submit = async (formData: GiftCardUpdateFormData) => {
|
||||
const result = await updateGiftCard({
|
||||
variables: {
|
||||
id: giftCard?.id,
|
||||
input: {
|
||||
tag: formData.tag,
|
||||
expirySettings: getGiftCardExpirySettingsInputData(formData)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result?.data?.giftCardUpdate?.errors;
|
||||
};
|
||||
|
||||
const formProps = useForm<GiftCardUpdateFormData>(getInitialData());
|
||||
|
||||
const { data, change, setChanged, hasChanged } = formProps;
|
||||
|
||||
const {
|
||||
isMetadataModified,
|
||||
isPrivateMetadataModified,
|
||||
makeChangeHandler: makeMetadataChangeHandler
|
||||
} = useMetadataChangeTrigger();
|
||||
|
||||
const changeMetadata = makeMetadataChangeHandler(change);
|
||||
|
||||
const submitData: GiftCardUpdateFormData = {
|
||||
...data,
|
||||
...getMetadata(data, isMetadataModified, isPrivateMetadataModified)
|
||||
};
|
||||
|
||||
const handleSubmit = createMetadataUpdateHandler(
|
||||
giftCard,
|
||||
submit,
|
||||
variables => updateMetadata({ variables }),
|
||||
variables => updatePrivateMetadata({ variables })
|
||||
);
|
||||
|
||||
const formSubmit = () =>
|
||||
handleFormSubmit(submitData, handleSubmit, setChanged);
|
||||
|
||||
const formErrors = getFormErrors(
|
||||
["tag", "expiryDate", "expiryPeriod"],
|
||||
updateGiftCardOpts?.data?.giftCardUpdate?.errors
|
||||
);
|
||||
|
||||
const providerValues = {
|
||||
...formProps,
|
||||
opts: updateGiftCardOpts,
|
||||
hasChanged,
|
||||
formErrors,
|
||||
submit: formSubmit,
|
||||
handlers: {
|
||||
changeMetadata
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<GiftCardUpdateFormContext.Provider value={providerValues}>
|
||||
{children}
|
||||
</GiftCardUpdateFormContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardUpdateFormProvider;
|
|
@ -0,0 +1,14 @@
|
|||
import { useContext } from "react";
|
||||
|
||||
import {
|
||||
GiftCardUpdateFormConsumerData,
|
||||
GiftCardUpdateFormContext
|
||||
} from "../GiftCardUpdateFormProvider";
|
||||
|
||||
const useGiftCardUpdate = (): Pick<GiftCardUpdateFormConsumerData, "opts"> => {
|
||||
const { opts } = useContext(GiftCardUpdateFormContext);
|
||||
|
||||
return { opts };
|
||||
};
|
||||
|
||||
export default useGiftCardUpdate;
|
|
@ -0,0 +1,20 @@
|
|||
import { UseFormResult } from "@saleor/hooks/useForm";
|
||||
import omit from "lodash/omit";
|
||||
import { useContext } from "react";
|
||||
|
||||
import {
|
||||
GiftCardUpdateFormContext,
|
||||
GiftCardUpdateFormData,
|
||||
GiftCardUpdateFormErrors
|
||||
} from "../GiftCardUpdateFormProvider";
|
||||
|
||||
type UseGiftCardUpdateFormProps = UseFormResult<GiftCardUpdateFormData> &
|
||||
GiftCardUpdateFormErrors;
|
||||
|
||||
const useGiftCardUpdate = (): UseGiftCardUpdateFormProps => {
|
||||
const giftCardUpdateFormProviderProps = useContext(GiftCardUpdateFormContext);
|
||||
|
||||
return omit(giftCardUpdateFormProviderProps, ["opts"]);
|
||||
};
|
||||
|
||||
export default useGiftCardUpdate;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardUpdateFormProvider";
|
||||
export { default } from "./GiftCardUpdateFormProvider";
|
116
src/giftCards/GiftCardUpdate/queries.ts
Normal file
116
src/giftCards/GiftCardUpdate/queries.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { fragmentUserBase } from "@saleor/fragments/auth";
|
||||
import { metadataFragment } from "@saleor/fragments/metadata";
|
||||
import { fragmentMoney } from "@saleor/fragments/products";
|
||||
import { fragmentTimePeriod } from "@saleor/fragments/timePeriod";
|
||||
import makeQuery from "@saleor/hooks/makeQuery";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import {
|
||||
GiftCardDetails,
|
||||
GiftCardDetailsVariables
|
||||
} from "./types/GiftCardDetails";
|
||||
|
||||
export const giftCardDataFragment = gql`
|
||||
${fragmentMoney}
|
||||
${metadataFragment}
|
||||
${fragmentUserBase}
|
||||
${fragmentTimePeriod}
|
||||
fragment GiftCardData on GiftCard {
|
||||
...MetadataFragment
|
||||
displayCode
|
||||
createdBy {
|
||||
...UserBase
|
||||
}
|
||||
product {
|
||||
id
|
||||
name
|
||||
}
|
||||
user {
|
||||
...UserBase
|
||||
}
|
||||
usedBy {
|
||||
...UserBase
|
||||
}
|
||||
usedByEmail
|
||||
createdByEmail
|
||||
app {
|
||||
id
|
||||
name
|
||||
}
|
||||
created
|
||||
expiryDate
|
||||
expiryType
|
||||
expiryPeriod {
|
||||
...TimePeriod
|
||||
}
|
||||
lastUsedOn
|
||||
isActive
|
||||
initialBalance {
|
||||
...Money
|
||||
}
|
||||
currentBalance {
|
||||
...Money
|
||||
}
|
||||
|
||||
id
|
||||
tag
|
||||
}
|
||||
`;
|
||||
|
||||
export const giftCardDetails = gql`
|
||||
${giftCardDataFragment}
|
||||
query GiftCardDetails($id: ID!) {
|
||||
giftCard(id: $id) {
|
||||
...GiftCardData
|
||||
events {
|
||||
expiry {
|
||||
expiryType
|
||||
expiryPeriod {
|
||||
...TimePeriod
|
||||
}
|
||||
expiryDate
|
||||
oldExpiryType
|
||||
oldExpiryPeriod {
|
||||
...TimePeriod
|
||||
}
|
||||
oldExpiryDate
|
||||
}
|
||||
id
|
||||
date
|
||||
type
|
||||
user {
|
||||
...UserBase
|
||||
}
|
||||
app {
|
||||
id
|
||||
name
|
||||
}
|
||||
message
|
||||
email
|
||||
orderId
|
||||
orderNumber
|
||||
tag
|
||||
oldTag
|
||||
balance {
|
||||
initialBalance {
|
||||
...Money
|
||||
}
|
||||
currentBalance {
|
||||
...Money
|
||||
}
|
||||
oldInitialBalance {
|
||||
...Money
|
||||
}
|
||||
oldCurrentBalance {
|
||||
...Money
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useGiftCardDetailsQuery = makeQuery<
|
||||
GiftCardDetails,
|
||||
GiftCardDetailsVariables
|
||||
>(giftCardDetails);
|
9
src/giftCards/GiftCardUpdate/types.ts
Normal file
9
src/giftCards/GiftCardUpdate/types.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { Dialog } from "@saleor/types";
|
||||
|
||||
export enum GiftCardUpdatePageActionParamsEnum {
|
||||
SET_BALANCE = "set-balance"
|
||||
}
|
||||
|
||||
export type GiftCardUpdatePageUrlQueryParams = Dialog<
|
||||
GiftCardUpdatePageActionParamsEnum
|
||||
>;
|
97
src/giftCards/GiftCardUpdate/types/GiftCardData.ts
Normal file
97
src/giftCards/GiftCardUpdate/types/GiftCardData.ts
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardExpiryTypeEnum, TimePeriodTypeEnum } from "./../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: GiftCardData
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardData_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_createdBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_product {
|
||||
__typename: "Product";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_user {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_usedBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardData_expiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardData_initialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData_currentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardData {
|
||||
__typename: "GiftCard";
|
||||
metadata: (GiftCardData_metadata | null)[];
|
||||
privateMetadata: (GiftCardData_privateMetadata | null)[];
|
||||
displayCode: string;
|
||||
createdBy: GiftCardData_createdBy | null;
|
||||
product: GiftCardData_product | null;
|
||||
user: GiftCardData_user | null;
|
||||
usedBy: GiftCardData_usedBy | null;
|
||||
usedByEmail: string | null;
|
||||
createdByEmail: string | null;
|
||||
app: GiftCardData_app | null;
|
||||
created: any;
|
||||
expiryDate: any | null;
|
||||
expiryType: GiftCardExpiryTypeEnum;
|
||||
expiryPeriod: GiftCardData_expiryPeriod | null;
|
||||
lastUsedOn: any | null;
|
||||
isActive: boolean;
|
||||
initialBalance: GiftCardData_initialBalance | null;
|
||||
currentBalance: GiftCardData_currentBalance | null;
|
||||
id: string;
|
||||
tag: string | null;
|
||||
}
|
190
src/giftCards/GiftCardUpdate/types/GiftCardDetails.ts
Normal file
190
src/giftCards/GiftCardUpdate/types/GiftCardDetails.ts
Normal file
|
@ -0,0 +1,190 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardExpiryTypeEnum, TimePeriodTypeEnum, GiftCardEventsEnum } from "./../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: GiftCardDetails
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardDetails_giftCard_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_createdBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_product {
|
||||
__typename: "Product";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_user {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_usedBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_expiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_initialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_currentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_expiry_expiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_expiry_oldExpiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_expiry {
|
||||
__typename: "GiftCardEventExpiry";
|
||||
expiryType: GiftCardExpiryTypeEnum | null;
|
||||
expiryPeriod: GiftCardDetails_giftCard_events_expiry_expiryPeriod | null;
|
||||
expiryDate: any | null;
|
||||
oldExpiryType: GiftCardExpiryTypeEnum | null;
|
||||
oldExpiryPeriod: GiftCardDetails_giftCard_events_expiry_oldExpiryPeriod | null;
|
||||
oldExpiryDate: any | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_user {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_balance_initialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_balance_currentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_balance_oldInitialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_balance_oldCurrentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events_balance {
|
||||
__typename: "GiftCardEventBalance";
|
||||
initialBalance: GiftCardDetails_giftCard_events_balance_initialBalance;
|
||||
currentBalance: GiftCardDetails_giftCard_events_balance_currentBalance;
|
||||
oldInitialBalance: GiftCardDetails_giftCard_events_balance_oldInitialBalance | null;
|
||||
oldCurrentBalance: GiftCardDetails_giftCard_events_balance_oldCurrentBalance | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard_events {
|
||||
__typename: "GiftCardEvent";
|
||||
expiry: GiftCardDetails_giftCard_events_expiry | null;
|
||||
id: string;
|
||||
date: any | null;
|
||||
type: GiftCardEventsEnum | null;
|
||||
user: GiftCardDetails_giftCard_events_user | null;
|
||||
app: GiftCardDetails_giftCard_events_app | null;
|
||||
message: string | null;
|
||||
email: string | null;
|
||||
orderId: string | null;
|
||||
orderNumber: string | null;
|
||||
tag: string | null;
|
||||
oldTag: string | null;
|
||||
balance: GiftCardDetails_giftCard_events_balance | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDetails_giftCard {
|
||||
__typename: "GiftCard";
|
||||
metadata: (GiftCardDetails_giftCard_metadata | null)[];
|
||||
privateMetadata: (GiftCardDetails_giftCard_privateMetadata | null)[];
|
||||
displayCode: string;
|
||||
createdBy: GiftCardDetails_giftCard_createdBy | null;
|
||||
product: GiftCardDetails_giftCard_product | null;
|
||||
user: GiftCardDetails_giftCard_user | null;
|
||||
usedBy: GiftCardDetails_giftCard_usedBy | null;
|
||||
usedByEmail: string | null;
|
||||
createdByEmail: string | null;
|
||||
app: GiftCardDetails_giftCard_app | null;
|
||||
created: any;
|
||||
expiryDate: any | null;
|
||||
expiryType: GiftCardExpiryTypeEnum;
|
||||
expiryPeriod: GiftCardDetails_giftCard_expiryPeriod | null;
|
||||
lastUsedOn: any | null;
|
||||
isActive: boolean;
|
||||
initialBalance: GiftCardDetails_giftCard_initialBalance | null;
|
||||
currentBalance: GiftCardDetails_giftCard_currentBalance | null;
|
||||
id: string;
|
||||
tag: string | null;
|
||||
events: GiftCardDetails_giftCard_events[];
|
||||
}
|
||||
|
||||
export interface GiftCardDetails {
|
||||
giftCard: GiftCardDetails_giftCard | null;
|
||||
}
|
||||
|
||||
export interface GiftCardDetailsVariables {
|
||||
id: string;
|
||||
}
|
118
src/giftCards/GiftCardUpdate/types/GiftCardUpdate.ts
Normal file
118
src/giftCards/GiftCardUpdate/types/GiftCardUpdate.ts
Normal file
|
@ -0,0 +1,118 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardUpdateInput, GiftCardErrorCode, GiftCardExpiryTypeEnum, TimePeriodTypeEnum } from "./../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: GiftCardUpdate
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_errors {
|
||||
__typename: "GiftCardError";
|
||||
code: GiftCardErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_createdBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_product {
|
||||
__typename: "Product";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_user {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_usedBy {
|
||||
__typename: "User";
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_expiryPeriod {
|
||||
__typename: "TimePeriod";
|
||||
amount: number;
|
||||
type: TimePeriodTypeEnum;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_initialBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard_currentBalance {
|
||||
__typename: "Money";
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate_giftCard {
|
||||
__typename: "GiftCard";
|
||||
metadata: (GiftCardUpdate_giftCardUpdate_giftCard_metadata | null)[];
|
||||
privateMetadata: (GiftCardUpdate_giftCardUpdate_giftCard_privateMetadata | null)[];
|
||||
displayCode: string;
|
||||
createdBy: GiftCardUpdate_giftCardUpdate_giftCard_createdBy | null;
|
||||
product: GiftCardUpdate_giftCardUpdate_giftCard_product | null;
|
||||
user: GiftCardUpdate_giftCardUpdate_giftCard_user | null;
|
||||
usedBy: GiftCardUpdate_giftCardUpdate_giftCard_usedBy | null;
|
||||
usedByEmail: string | null;
|
||||
createdByEmail: string | null;
|
||||
app: GiftCardUpdate_giftCardUpdate_giftCard_app | null;
|
||||
created: any;
|
||||
expiryDate: any | null;
|
||||
expiryType: GiftCardExpiryTypeEnum;
|
||||
expiryPeriod: GiftCardUpdate_giftCardUpdate_giftCard_expiryPeriod | null;
|
||||
lastUsedOn: any | null;
|
||||
isActive: boolean;
|
||||
initialBalance: GiftCardUpdate_giftCardUpdate_giftCard_initialBalance | null;
|
||||
currentBalance: GiftCardUpdate_giftCardUpdate_giftCard_currentBalance | null;
|
||||
id: string;
|
||||
tag: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate_giftCardUpdate {
|
||||
__typename: "GiftCardUpdate";
|
||||
errors: GiftCardUpdate_giftCardUpdate_errors[];
|
||||
giftCard: GiftCardUpdate_giftCardUpdate_giftCard | null;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdate {
|
||||
giftCardUpdate: GiftCardUpdate_giftCardUpdate | null;
|
||||
}
|
||||
|
||||
export interface GiftCardUpdateVariables {
|
||||
id: string;
|
||||
input: GiftCardUpdateInput;
|
||||
}
|
46
src/giftCards/GiftCardsList/GiftCardsList.tsx
Normal file
46
src/giftCards/GiftCardsList/GiftCardsList.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import Container from "@saleor/components/Container";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import React from "react";
|
||||
|
||||
import GiftCardCreateDialog from "../GiftCardCreateDialog";
|
||||
import { giftCardsListUrl } from "../urls";
|
||||
import GiftCardsListHeader from "./GiftCardsListHeader";
|
||||
import GiftCardsListTable from "./GiftCardsListTable";
|
||||
import { GiftCardsListProvider } from "./providers/GiftCardsListProvider";
|
||||
import {
|
||||
GiftCardListActionParamsEnum,
|
||||
GiftCardListUrlQueryParams
|
||||
} from "./types";
|
||||
|
||||
interface GiftCardsListProps {
|
||||
params: GiftCardListUrlQueryParams;
|
||||
}
|
||||
|
||||
const GiftCardsList: React.FC<GiftCardsListProps> = ({ params }) => {
|
||||
const navigate = useNavigator();
|
||||
|
||||
const [openModal, closeModal] = createDialogActionHandlers<
|
||||
GiftCardListActionParamsEnum,
|
||||
GiftCardListUrlQueryParams
|
||||
>(navigate, giftCardsListUrl, params);
|
||||
|
||||
const openCreateModal = () => openModal(GiftCardListActionParamsEnum.CREATE);
|
||||
|
||||
return (
|
||||
<>
|
||||
<GiftCardsListProvider params={params}>
|
||||
<Container>
|
||||
<GiftCardsListHeader onIssueButtonClick={openCreateModal} />
|
||||
<GiftCardsListTable />
|
||||
</Container>
|
||||
</GiftCardsListProvider>
|
||||
<GiftCardCreateDialog
|
||||
open={params?.action === GiftCardListActionParamsEnum.CREATE}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardsList;
|
49
src/giftCards/GiftCardsList/GiftCardsListHeader.tsx
Normal file
49
src/giftCards/GiftCardsList/GiftCardsListHeader.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { Button } from "@material-ui/core";
|
||||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||
// import CardMenu, { CardMenuItem } from "@saleor/components/CardMenu";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { giftCardsListHeaderMenuItemsMessages as messages } from "./messages";
|
||||
|
||||
interface GiftCardsListHeaderProps {
|
||||
onIssueButtonClick: () => void;
|
||||
}
|
||||
|
||||
const GiftCardsListHeader: React.FC<GiftCardsListHeaderProps> = ({
|
||||
onIssueButtonClick
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
// const menuItems: CardMenuItem[] = [
|
||||
// {
|
||||
// label: intl.formatMessage(messages.settings),
|
||||
// testId: "settingsMenuItem"
|
||||
// // onSelect:
|
||||
// },
|
||||
// {
|
||||
// label: intl.formatMessage(messages.bulkIssue),
|
||||
// testId: "bulkIssueMenuItem"
|
||||
// // onSelect:
|
||||
// },
|
||||
// {
|
||||
// label: intl.formatMessage(messages.exportCodes),
|
||||
// testId: "exportCodesMenuItem"
|
||||
// // onSelect:
|
||||
// }
|
||||
// ];
|
||||
|
||||
return (
|
||||
<PageHeader title={intl.formatMessage(sectionNames.giftCards)}>
|
||||
{/* <CardMenu menuItems={menuItems} data-test="menu" /> */}
|
||||
<HorizontalSpacer spacing={2} />
|
||||
<Button color="primary" variant="contained" onClick={onIssueButtonClick}>
|
||||
{intl.formatMessage(messages.issueButtonLabel)}
|
||||
</Button>
|
||||
</PageHeader>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardsListHeader;
|
|
@ -0,0 +1,147 @@
|
|||
import {
|
||||
Card,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
Typography
|
||||
} from "@material-ui/core";
|
||||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import DeleteIconButton from "@saleor/components/DeleteIconButton";
|
||||
import Link from "@saleor/components/Link";
|
||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import StatusChip from "@saleor/components/StatusChip";
|
||||
import { StatusType } from "@saleor/components/StatusChip/types";
|
||||
import { customerUrl } from "@saleor/customers/urls";
|
||||
import { giftCardUrl } from "@saleor/giftCards/urls";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import { renderCollection } from "@saleor/misc";
|
||||
import { productUrl } from "@saleor/products/urls";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { giftCardsListTableMessages as messages } from "../messages";
|
||||
import useGiftCardList from "../providers/hooks/useGiftCardList";
|
||||
import useGiftCardListBulkActions from "../providers/hooks/useGiftCardListBulkActions";
|
||||
import { useTableStyles as useStyles } from "../styles";
|
||||
import GiftCardsListTableFooter from "./GiftCardsListTableFooter";
|
||||
import GiftCardsListTableHeader from "./GiftCardsListTableHeader";
|
||||
|
||||
const PLACEHOLDER = "-";
|
||||
|
||||
const GiftCardsListTable: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
const navigate = useNavigator();
|
||||
const { giftCards, numberOfColumns, loading } = useGiftCardList();
|
||||
const { toggle, isSelected } = useGiftCardListBulkActions();
|
||||
|
||||
const redirectToGiftCardUpdate = (id: string) => () =>
|
||||
navigate(giftCardUrl(id));
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<ResponsiveTable>
|
||||
<GiftCardsListTableHeader />
|
||||
<GiftCardsListTableFooter />
|
||||
<TableBody>
|
||||
{renderCollection(
|
||||
giftCards,
|
||||
({
|
||||
id,
|
||||
displayCode,
|
||||
usedBy,
|
||||
usedByEmail,
|
||||
tag,
|
||||
isActive,
|
||||
product,
|
||||
currentBalance
|
||||
}) => (
|
||||
<TableRow
|
||||
onClick={redirectToGiftCardUpdate(id)}
|
||||
className={classes.row}
|
||||
key={id}
|
||||
>
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
disableClickPropagation
|
||||
checked={isSelected(id)}
|
||||
onChange={() => toggle(id)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colCardCode}>
|
||||
<div className={classes.cardCodeContainer}>
|
||||
<Typography>
|
||||
{intl.formatMessage(messages.codeEndingWithLabel, {
|
||||
displayCode
|
||||
})}
|
||||
</Typography>
|
||||
{!isActive && (
|
||||
<>
|
||||
<HorizontalSpacer spacing={2} />
|
||||
<StatusChip
|
||||
size="md"
|
||||
status={StatusType.ERROR}
|
||||
label={intl.formatMessage(
|
||||
messages.giftCardDisabledLabel
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>{tag || PLACEHOLDER}</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{product ? (
|
||||
<Link onClick={() => navigate(productUrl(product?.id))}>
|
||||
{product?.name}
|
||||
</Link>
|
||||
) : (
|
||||
PLACEHOLDER
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{usedBy ? (
|
||||
<Link onClick={() => navigate(customerUrl(usedBy?.id))}>
|
||||
{`${usedBy?.firstName} ${usedBy?.lastName}`}
|
||||
</Link>
|
||||
) : (
|
||||
<Typography noWrap>{usedByEmail || PLACEHOLDER}</Typography>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="right" className={classes.colBalance}>
|
||||
<div className={classes.moneyContainer}>
|
||||
<Typography variant="caption">
|
||||
{currentBalance.currency}
|
||||
</Typography>
|
||||
<HorizontalSpacer spacing={0.5} />
|
||||
<Typography>{currentBalance.amount}</Typography>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colDelete}>
|
||||
<DeleteIconButton />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
),
|
||||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
<Skeleton>
|
||||
{!loading && (
|
||||
<FormattedMessage {...messages.noGiftCardsFound} />
|
||||
)}
|
||||
</Skeleton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</ResponsiveTable>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardsListTable;
|
|
@ -0,0 +1,43 @@
|
|||
import { TableFooter, TableRow } from "@material-ui/core";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import usePaginator from "@saleor/hooks/usePaginator";
|
||||
import React from "react";
|
||||
|
||||
import useGiftCardList from "../providers/hooks/useGiftCardList";
|
||||
|
||||
const GiftCardsListTableFooter: React.FC = () => {
|
||||
const paginate = usePaginator();
|
||||
|
||||
const {
|
||||
settings,
|
||||
updateListSettings,
|
||||
pageInfo: apiPageInfo,
|
||||
paginationState,
|
||||
params,
|
||||
numberOfColumns
|
||||
} = useGiftCardList();
|
||||
|
||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||
apiPageInfo,
|
||||
paginationState,
|
||||
params
|
||||
);
|
||||
|
||||
return (
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TablePagination
|
||||
settings={settings}
|
||||
colSpan={numberOfColumns}
|
||||
hasNextPage={pageInfo ? pageInfo.hasNextPage : false}
|
||||
onNextPage={loadNextPage}
|
||||
onUpdateListSettings={updateListSettings}
|
||||
onPreviousPage={loadPreviousPage}
|
||||
hasPreviousPage={pageInfo ? pageInfo.hasPreviousPage : false}
|
||||
/>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardsListTableFooter;
|
|
@ -0,0 +1,83 @@
|
|||
import { TableCell } from "@material-ui/core";
|
||||
import TableCellHeader, {
|
||||
TableCellHeaderProps
|
||||
} from "@saleor/components/TableCellHeader";
|
||||
import TableHead from "@saleor/components/TableHead";
|
||||
import Label, {
|
||||
LabelSizes
|
||||
} from "@saleor/orders/components/OrderHistory/Label";
|
||||
import React from "react";
|
||||
import { MessageDescriptor, useIntl } from "react-intl";
|
||||
|
||||
import { giftCardsListTableMessages as messages } from "../messages";
|
||||
import useGiftCardList from "../providers/hooks/useGiftCardList";
|
||||
import useGiftCardListBulkActions from "../providers/hooks/useGiftCardListBulkActions";
|
||||
import { useTableStyles as useStyles } from "../styles";
|
||||
|
||||
interface HeaderItem {
|
||||
title?: MessageDescriptor;
|
||||
options?: TableCellHeaderProps;
|
||||
}
|
||||
|
||||
const GiftCardsListTableHeader: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
const { giftCards, numberOfColumns, loading } = useGiftCardList();
|
||||
const { toggleAll, listElements } = useGiftCardListBulkActions();
|
||||
|
||||
const headerItems: HeaderItem[] = [
|
||||
{
|
||||
title: messages.giftCardsTableColumnGiftCardTitle,
|
||||
options: {
|
||||
className: classes.colCardCode,
|
||||
textAlign: "left"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: messages.giftCardsTableColumnTagTitle
|
||||
},
|
||||
{
|
||||
title: messages.giftCardsTableColumnProductTitle
|
||||
},
|
||||
{
|
||||
title: messages.giftCardsTableColumnCustomerTitle
|
||||
},
|
||||
{
|
||||
title: messages.giftCardsTableColumnBalanceTitle,
|
||||
options: {
|
||||
className: classes.colBalance,
|
||||
textAlign: "right"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<colgroup>
|
||||
<col />
|
||||
<col className={classes.colCardCode} />
|
||||
<col className={classes.colBase} />
|
||||
<col className={classes.colBase} />
|
||||
<col className={classes.colBase} />
|
||||
<col className={classes.colBalance} />
|
||||
<col className={classes.colDelete} />
|
||||
</colgroup>
|
||||
<TableHead
|
||||
disabled={loading}
|
||||
colSpan={numberOfColumns}
|
||||
selected={listElements.length}
|
||||
items={giftCards}
|
||||
toggleAll={toggleAll}
|
||||
>
|
||||
{headerItems.map(({ title, options }) => (
|
||||
<TableCellHeader {...options}>
|
||||
<Label text={intl.formatMessage(title)} size={LabelSizes.md} />
|
||||
</TableCellHeader>
|
||||
))}
|
||||
<TableCell className={classes.colDelete} />
|
||||
</TableHead>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardsListTableHeader;
|
2
src/giftCards/GiftCardsList/GiftCardsListTable/index.tsx
Normal file
2
src/giftCards/GiftCardsList/GiftCardsListTable/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardsListTable";
|
||||
export { default } from "./GiftCardsListTable";
|
2
src/giftCards/GiftCardsList/index.tsx
Normal file
2
src/giftCards/GiftCardsList/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardsList";
|
||||
export { default } from "./GiftCardsList";
|
55
src/giftCards/GiftCardsList/messages.ts
Normal file
55
src/giftCards/GiftCardsList/messages.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardsListHeaderMenuItemsMessages = defineMessages({
|
||||
settings: {
|
||||
defaultMessage: "Settings",
|
||||
description: "GiftCardsListHeader menu item settings"
|
||||
},
|
||||
bulkIssue: {
|
||||
defaultMessage: "Bulk Issue",
|
||||
description: "GiftCardsListHeader menu item settings"
|
||||
},
|
||||
exportCodes: {
|
||||
defaultMessage: "Export card codes",
|
||||
description: "GiftCardsListHeader menu item settings"
|
||||
},
|
||||
issueButtonLabel: {
|
||||
defaultMessage: "Issue card",
|
||||
description: "GiftCardsListHeader issue button label"
|
||||
}
|
||||
});
|
||||
|
||||
export const giftCardsListTableMessages = defineMessages({
|
||||
giftCardsTableColumnGiftCardTitle: {
|
||||
defaultMessage: "Gift Card",
|
||||
description: "GiftCardsListTable column title gift card"
|
||||
},
|
||||
giftCardsTableColumnTagTitle: {
|
||||
defaultMessage: "Tag",
|
||||
description: "GiftCardsListTable column title tag"
|
||||
},
|
||||
giftCardsTableColumnProductTitle: {
|
||||
defaultMessage: "Product",
|
||||
description: "GiftCardsListTable column title product"
|
||||
},
|
||||
giftCardsTableColumnCustomerTitle: {
|
||||
defaultMessage: "Used by",
|
||||
description: "GiftCardsListTable column title customer"
|
||||
},
|
||||
giftCardsTableColumnBalanceTitle: {
|
||||
defaultMessage: "Balance",
|
||||
description: "GiftCardsListTable column title balance"
|
||||
},
|
||||
codeEndingWithLabel: {
|
||||
defaultMessage: "Code ending with {displayCode}",
|
||||
description: "GiftCardsListTable code ending with label"
|
||||
},
|
||||
giftCardDisabledLabel: {
|
||||
defaultMessage: "Disabled",
|
||||
description: "GiftCardsListTable disabled label"
|
||||
},
|
||||
noGiftCardsFound: {
|
||||
defaultMessage: "No gift cards found",
|
||||
description: "GiftCardsListTable no cards found title"
|
||||
}
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue