Closed porl closed 6 months ago
Hi @porl If I understand correctly you have a custom field in the order items. So every time you add an item in the order you need to pass this information as well. To achieve this result you need to change the correct gql query and pass this extra information into the right methods. i.e addItemToOrder You can test your gql query in the Vendure playground and then implement the functionality in the frontend.
Yes, that's what I'm trying to do. Basically copy the "engravable" product from the vendure docs to this qwik starter template.
What I don't understand is how to do it with all the auto-generating code etc. What parts would I change to make the typescript generate correctly for example?
You need to change this variable and generate the correct types based on your environment
Hi @gioboa
Yes, that's correct. I did as you suggested and tried the query manually in the playground and that works easily enough:
mutation {
addItemToOrder(productVariantId: 119, quantity: 1, customFields: {customText: "customised text"}) {
...on Order {
id
code
totalQuantity
totalWithTax
lines {
productVariant {
name
}
customFields {
customText
}
quantity
linePriceWithTax
}
}
...on ErrorResult {
errorCode
message
}
}
}
Trying to add this extra parameter to src/providers/shop/orders/order.ts
is where I'm stuck though. I tried just adjusting the gql mutation string template, but that did not work by itself. Trying to edit export const addItemToOrderMutation = async ...
I think is what I need to do, but I don't know what needs to go there. It references generated/graphql.ts
AddItemToOrderMutation
but that has no reference to the custom field parameter. The fact that this file is in the generated directory makes me unsure if I should touch it or it is generated from something elsewhere I need to change instead.
Sorry if it is unclear - I understand what needs to be sent to the Vendure backend, but the qwik starter template is using a lot of autogenerated code and I don't understand how to add in this custom field correctly.
Did you regenerate the schemas from your backend environment?
Sorry, I'm not sure. I'm using plain Vendure in the backend and the Vendure Qwik Starter template in the frontend.
Looking at generated/schema.graphql
I can see ProductCustomFields contains printfulProductId
which I think is from the standard test vendure demo site, and OrderLine customFields is just set to JSON (implying it does not have any).
How do I regenerate this file? I assume I also need to regenerate the graphql.ts
file in the same directory. All other files show modifications in git so I assume they are being generated when the pnpm start
command is run, but those two files are unchanged. Is there a pnpm command to rebuild these from the vendure backend?
Update:
I found and ran the command pnpm run generate-shop
and nothing seemed to change. Ran it again and this time it did update the graphql-shop.ts
and schema-shop.graphql
files.
Hopefully this will get me in the right direction. I assume I need to update the order.ts
mutation gql template string to match? It is currently as below:
gql`
mutation addItemToOrder($productVariantId: ID!, $quantity: Int!) {
addItemToOrder(productVariantId: $productVariantId, quantity: $quantity) {
...OrderDetail
... on ErrorResult {
errorCode
message
}
}
}
`;
How do I add an (optional) customfields parameter to this? The graphql.ts
file shows the following:
export type AddItemToOrderMutationVariables = Exact<{
productVariantId: Scalars['ID'];
quantity: Scalars['Int'];
}>;
But I'm not sure if this should be regenerated somehow or if it needs to be manually edited (or if I'm chasing a red-herring).
Thanks for your patience
Hi @porl
You are on the right track. You need to make sure that when you run pnpm run generate-shop
, you make sure it is pointing at the url of the API that contains you custom fields on OrderLine.
If we look at the codegen-shop.ts
script, we can see that the URL to be used is determined by environment variables, and based on that, one of these 3 URLs will be used.
So it looks like if you set the IS_LOCAL
env var, it should do the codegen from your localhost which is probably what you want.
IS_LOCAL=true pnpm run generate-shop
Let me know if that works
Hi @michaelbromley
Very sorry for the slow replies. Currently sick so only jumping on here every so often while I recover.
I didn't think to try setting the environment variable, but earlier on I did set all three URLs to be the same (pointing to localhost).
As I mentioned before, some things changed to match, however I noticed the routes/products/[...slug]/index.tsx
file references the following:
import { Order, OrderLine, Product } from '~/generated/graphql';
and
import { addItemToOrderMutation } from '~/providers/shop/orders/order';
which references
import {
ActiveOrderQuery,
AddItemToOrderMutation,
AdjustOrderLineMutation,
CreateAddressInput,
CreateCustomerInput,
Order,
OrderByCodeQuery,
RemoveOrderLineMutation,
SetCustomerForOrderMutation,
SetOrderShippingAddressMutation,
SetOrderShippingMethodMutation,
} from '~/generated/graphql';
as well as containing the 'hardcoded' gql template statements I pasted in the last reply.
I assumed this meant that the generated/graphql.ts
file was supposed to be regenerated from the server as well, but perhaps this is instead an old version and those files should be updated to point to the `graphql-shop.ts
file instead?
For reference, the graphql-shop.ts
file now contains the following:
export type OrderLine = Node & {
__typename?: 'OrderLine';
createdAt: Scalars['DateTime']['output'];
customFields?: Maybe<OrderLineCustomFields>;
/** The price of the line including discounts, excluding tax */
...
}
and
export type OrderLineCustomFields = {
__typename?: 'OrderLineCustomFields';
customText?: Maybe<Scalars['String']['output']>;
};
export type OrderLineCustomFieldsInput = {
customText?: InputMaybe<Scalars['String']['input']>;
};
Finally back at work. I changed the providers
and routes
files to point to generated/graphql-shop.ts
rather than generated/graphql.ts
and the site appears to still work correctly.
Using the following code on a product page I can get the site to tell me if a product has the customisable field (which would then be used to display the text field):
{productSignal.value.customFields?.allowsCustomText && (
<div>CUSTOMISABLE!</div>
)}
Unfortunately I am still stuck here - I don't know what to change in the order.ts
or similar files to send the correct info back as a mutation (let alone display it in cart, make it editable etc). The Vendure docs show in detail what is needed in the backend for an "engravable" product, however it would be really helpful if one or more of the storefront starters showed how to integrate this.
Hi @porl
So to set the value of the custom field on the OrderLine, you need to find the addItemToOrder
mutation and add the custom field value(s) as the "customFields" input argument to the mutation. An example is given here: https://docs.vendure.io/guides/how-to/configurable-products/#setting-the-custom-field-value
That means changing these lines to accept the "customFields" input:
mutation addItemToOrder($productVariantId: ID!, $quantity: Int!, $customFields: OrderLineCustomFieldsInput) {
addItemToOrder(productVariantId: $productVariantId, quantity: $quantity, customFields: $customFields) {
...OrderDetail
... on ErrorResult {
errorCode
message
}
}
}
and likewise add the argument to this function
Thank you! That has given me enough to go by I believe. I got some test text sent through a custom field. I still need to build the interface but that part should be independent from all this so I appreciate all the help.
Sorry to reopen - submitting the custom field to the backend works perfectly (I can use a text field to add custom text to a product and the order shows the custom text in the admin side), however I can't seem to get the field info back for pages such as the cart/checkout etc.
I noticed in the graphql-shop.ts
generated file there is the following (chopped for brevity):
export const OrderDetailFragmentDoc = gql`
fragment OrderDetail on Order {
__typename
id
code
active
createdAt
state
...
lines {
id
...
productVariant {
...
product {
id
slug
customFields {
allowsCustomText
}
}
}
customFields {
customText
}
}
}
`;
Which has the custom fields as expected. However the providers/shop.orders/order.ts
contains (again chopped for brevity):
gql`
fragment OrderDetail on Order {
__typename
id
code
active
createdAt
state
currencyCode
totalQuantity
subTotal
subTotalWithTax
taxSummary {
description
taxRate
taxTotal
}
shippingWithTax
totalWithTax
customer {
id
firstName
lastName
emailAddress
}
shippingAddress {
fullName
streetLine1
streetLine2
company
city
province
postalCode
countryCode
phoneNumber
}
shippingLines {
shippingMethod {
id
name
}
priceWithTax
}
lines {
id
...
productVariant {
...
product {
id
slug
}
}
}
}
`;
Which lacks the custom fields. Trying to add them in here to match however, gives me the warning
Warning: fragment with name OrderDetail already exists.
graphql-tag enforces all fragment names across your application to be unique
and there is no sign of the custom field values (or keys) in the order object on the front end. For a quick test, I am just using JSON.stringify(line)
on the order line object in the CartContents.tsx
component but only can get the "default" values - e.g. for the product I only have keys for id
and slug
.
Is there a reason that order.ts
doubles up this gql code? I assume it should be overriding the default in order to only get info we want, but then how can I avoid the warning? And why is the warning not there when the content is exactly as it was without the custom fields? That is still not the same as the graphql-shop
one. Am I in the wrong spot trying to add those fields to it? As I mentioned previously, I updated the imports at the top to point to graphql-shop
instead of just graphql
.
Update - still getting that warning, but after stopping and starting the server a couple of times it at least has the fields in the line object.
I would like to clean things up so I don't get the warning, but at least I can keep working.
Hi,
I'm not sure why there are 2 almost identical fragments. The query & fragment in admin/order.ts
does not even appear to be used currently.
To be honest I think the graphql setup in this project is way over-complicated and in need of a re-think. It is too difficult to figure out what to change. I recently discovered https://gql-tada.0no.co and started using it on another Vendure project and it is much, much better and simpler to use. Maybe you can check that out if you like.
Thanks for the recommendation. At least I know I'm not the only one that is finding the graphql generators etc complicated!
It would be great if there were a "quick starter template" that was a little more directly made for the basic Vendure install. I'm not generally a fan of hard-coding things, but maybe for a quick template it would be better to just manually create (or generate externally) the gql statements? Having auto-generated code is great for flexibility, but usually if I'm looking for a starter template I am looking to see how things work and learn a platform before I extend things for myself.
Having something more "direct" and then maybe some examples on how to add fields (taking the Vendure docs examples of custom fields and configurable products I think would be more than enough to get someone like me going. I think even the generation of the typescript functions could be pulled out to be external and just show similar info to the Vendure docs for manually adding more.
Obviously I'm not trying to imply any of this as demands or "you should do this!". I totally understand the amount of work that goes into these things. I just thought it was a good opportunity to throw in my ideal setup thoughts while the possibility of rethinking things is there.
Thanks again for your help! I'll mark this as closed (again) as the warning message, while unfortunate, is not stopping me from achieving what the thread is about.
I've been evaluating this starter template for a custom shop site and have now successfully worked out how to determine if a product or variant has a customfield attached to it.
I am basically following the "configurable products" server side tutorial here https://docs.vendure.io/guides/how-to/configurable-products/ (though with slightly different field names).
How do I add a text field to the product page with the correct code to work with the
addItemToOrder
mutation? I see the generatedschema-shop.graphql
file contains the correct field:and the
graphql-shop.ts
file has types associated with it too. Do I need to change relevant functions inorder.ts
? I assume I change it there somehow and then also change the call fromproducts/index.tsx
to match, but I'm not sure what to put in for the parameter type etc.Sorry for the ignorant question, I'm moving across from an old php-based shop to vendure as a headless system and there are a lot of differences to learn at once!