I'm trying to simulate the scenario where you, as a customer, have ordered a product from an online web shop and want to track the package.
So I am currently creating 3 marked up emails (as it probably would in a real life scenario) where the first email is the order confirmation, the second email is "order on the way" and the third email is "delivered". Pretty much everything is the same in all three emails.
The differences in these emails are the orderStatus that will show on the card:
"orderStatus": "[...]/OrderProcessing"
"orderStatus": "[...]/OrderInTransit"
"orderStatus": "[...]/OrderDelivered" (can't post more than 2 links..)
Here's my confirmation email markup atm:
<!DOCTYPE html>
<html>
<head>
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "ParcelDelivery",
"deliveryAddress": {
"#type": "PostalAddress",
"name": "Firstname Lastname",
"streetAddress": "2nd Street",
"addressLocality": "City",
"addressRegion": "State",
"addressCountry": "Country",
"postalCode": "12345"
},
"expectedArrivalUntil": "2016-08-03T12:00-24:00",
"carrier": {
"#type": "Organization",
"name": "Shipping Company"
},
"itemShipped": {
"#type": "Product",
"name": "Test Product"
},
"trackingNumber": "1234567890",
"trackingUrl": "some url",
"partOfOrder": {
"#type": "Order",
"orderNumber": "555555",
"merchant": {
"#type": "Organization",
"name": "Some web shop"
},
"orderStatus": "http://schema.org/OrderProcessing"
}
}
</script>
</head>
<body>
<p>
Confirmation email
</p>
</body>
</html>
I'm trying to achieve that these three emails should just update the order status of the first card that shows up. But instead, after I've sent the confirmation email, another card shows up when I send the "order on the way" email. Is it possible to override this somehow? I mean, as a user, it can be confusing that you have 2 cards when you only ordered 1 product.
Image after the first email is sent
Image after the second email is sent
Sorry for the swedish language in the screenshots, but you can probably understand what I mean anyway.
Edit: For some reason, when I now use the itemShipped.name = Test Product, I get a really cool jacket as an image.
I solved this problem by having the first mail tagged as
"#type": "Order"
instead of
"#type": "ParcelDelivery"
I figured since the first email is just a reciept of your order, it can't be tagged as ParcelDelivery since Google probably recognizes this as two different parcels. I also used the same orderNumber in all three mails. This resulted in one single card, on which the status was updated. I don't know if this is how it's meant to be used but it works for now atleast.
Related
In the ABP framework, the tutorial for version 5.1 says to:
Use Enum:enum-type:enum-value naming convention to localize the enum members.
e.g. "Enum:BookType:1": "Adventure"
However, this does not work when using the abp-select tag helper. I can see from the source code for abp-select that the expected format is actually:
Enum:enum-type.enum-toString
e.g. "Enum:BookType.Adventure": "Adventure"
So the documentation is inaccurate, but not a problem, as soon as I changed the resource file enums to the correct format abp-select localised the display values as expected.
However, the datatables source code for the Book List in the same tutorial then breaks:
columnDefs: [
{
title: l('Type'),
data: "type",
render: function (data) {
return l('Enum:BookType:' + data);
}
}
This code expects the enum format to be Enum:enum-type:enum-value and as data is passed back as an int and not the string representation of the enum, the datatable doesn't show the localised data.
As a work around, I am diverging from the tutorial instructions and binding the datatable to a BookDto where BookType is mapped to a string, not an enum. Feels a bit cludgy though.
Am I missing something here ABP?
Great product but this tutorial needs updating either way.
I ran into the same issue but solved it by updating the localization file en.json to match the enum value stored in the database and then changing the book.component.html file to match the abpLocalization property.
When I followed the official documentation at abp, I got this result:
First run with fallback string in HTML component
Acme.BookStore.Application.Shared/Localization/en.json
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:BookStore": "Book Store",
"Menu:Books": "Books",
"Actions": "Actions",
"Close": "Close",
"Delete": "Delete",
"Edit": "Edit",
"PublishDate": "Publish date",
"NewBook": "New book",
"Name": "Name",
"Type": "Type",
"Price": "Price",
"CreationTime": "Creation time",
"AreYouSure": "Are you sure?",
"AreYouSureToDelete": "Are you sure you want to delete this item?",
"Enum:BookType.0": "Undefined",
"Enum:BookType.1": "Adventure",
"Enum:BookType.2": "Biography",
"Enum:BookType.3": "Dystopia",
"Enum:BookType.4": "Fantastic",
"Enum:BookType.5": "Horror",
"Enum:BookType.6": "Science",
"Enum:BookType.7": "Science fiction",
"Enum:BookType.8": "Poetry"
}
}
book.component.html in the angular project
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ '::Menu:Books' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6"></div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default>
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column>
<ngx-datatable-column [name]="'::Type' | abpLocalization" prop="type">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ '::Enum:BookType.' + row.type | abpLocalization }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::PublishDate' | abpLocalization" prop="publishDate">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.publishDate | date }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Price' | abpLocalization" prop="price">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.price | currency }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
As you can see I have replaced the ":" with a "." as in the localization file.
After change to source-code I get this result:
Enums now translated correctly
I hope this helps you and others struggling with the same issue :)
I just had the same issue. The problem is a mismatch between the declaration of the localization file wrt the usage in the JS code.
In the localization file you can find keys like:
"Enum:BookType.Adventure": "Adventure"
while in the JavaScript it is used:
render: function (data) {
return l('Enum:BookType:' + data);
}
Thus either you change the localization keys as e.g. "Enum:BookType:Adventure": "Adventure" (with ':') or you change the code with this function:
render: function (data) {
return l('Enum:BookType.' + data);
}
where the '.' is concatenated instead of ':'
I have two datasets containing data gathered automatically by AI and another data gathered manually by humans. I currently display these into two separate column charts using Chartkick for Rails:
As shown above, the AI data is displayed as a stacked column chart that shows the breakdown of the confirmed, rejected, and unverified data because we still do confirmation checks to see the accuracy of our AI while the Human Operated Data is displayed as is, hence, no need to use a stacked column chart.
Now, what I want to achieve is to display the AI and Human Operated Data side by side (grouped), while maintaining the stacked property of the AI Data. So it should look like this:
The code that I currently have for the two separate charts are:
controller
# Data for Stacked Column Chart
#ai_operated_data = [
{
name: "Confirmed",
data: PotentialViolator.where(confirmation_status: 1).group_by_week(:capture_time).count
},
{
name: "Rejected",
data: PotentialViolator.where(confirmation_status: 0).group_by_week(:capture_time).count
},
{
name: "Unverified",
data: PotentialViolator.where(confirmation_status: -1).group_by_week(:capture_time).count
}
]
# Data for Single Column Chart
#human_operated_data = [
{
name: "Human Operated Data",
data: ManuallyCaughtViolator.group_by_week(:capture_time).count
}
]
view
<div class="ui container">
<h1>Performance Analytics</h1>
<div class="ui divider"></div>
<%= column_chart #ai_operated_data, stacked: true %>
<%= column_chart #human_operated_data %>
</div>
I was able to find the an example from the Chartkick.js examples and found out that there's just the stack option which you can pass as a parameter to specify if a series will be a part of the stack or not.
My final code in my view now looks like:
<%= column_chart [
{
name: "Confirmed AI-PWD Operated Data",
data: PotentialViolator.where(confirmation_status: 1).group_by_week(:capture_time).count,
stack: "stack 1"
},
{
name: "Rejected AI-PWD Operated Data",
data: PotentialViolator.where(confirmation_status: 0).group_by_week(:capture_time).count,
stack: "stack 1"
},
{
name: "Unverified AI-PWD Operated Data",
data: PotentialViolator.where(confirmation_status: -1).group_by_week(:capture_time).count,
stack: "stack 1"
},
{
name: "PWD-Operated Data",
data: ManuallyCaughtViolator.group_by_week(:capture_time).count,
stack: "stack 2"
}
], stacked: true
%>
So it produces this chart:
I am currently building an angular.js social media platform and am trying to display facebook posts on my feeds page for facebook. I currently have this:
<div id='fb-root'>
<div ng-repeat="post in facebook">
Test: {{post}}
</div>
</div>
which returns my Test post as:
[{"id":"4681211244366_4681199684077","from":{"id":"4681211244366","name":"Zachy Bear Jones"},"story":"Zachy Bear Jones and Alexander J. Marrs are now friends.","story_tags":{"0":[{"id":"4681211244366","name":"Zachy Bear Jones","offset":0,"length":16,"type":"user"}],"21":[{"id":"10205311345929912","name":"Alexander J. Marrs","offset":21,"length":18,"type":"user"}]},"actions":[{"name":"Comment","link":"https://www.facebook.com/4681211244366/posts/4681199684077"},{"name":"Like","link":"https://www.facebook.com/4681211244366/posts/4681199684077"}],"privacy":{"value":""},"type":"status","status_type":"approved_friend","created_time":"2014-10-11T21:33:29+0000","updated_time":"2014-10-11T21:33:29+0000"},{"id":"4681211244366_4678763463173pmpmymife","from":{"id":"4681211244366","name":"Zachy Bear Jones"},"story":"Zachy Bear Jones commented on a status.","story_tags":{"0":[{"id":"4681211244366","name":"Zachy Bear Jones","offset":0,"length":16,"type":"user"}]},"privacy":{"value":""},"type":"status","application":{"name":"Facebook for iPhone","namespace":"fbiphone","id":"6628568379"},"created_time":"2014-10-11T08:20:12+0000","updated_time":"2014-10-11T08:20:12+0000"},{"id":"4681211244366_4676849935336","from":{"id":"4681211244366","name":"Zachy Bear Jones"},"story":"Zachy Bear Jones likes a photo.","story_tags":{"0":[{"id":"4681211244366","name":"Zachy Bear Jones","offset":0,"length":16,"type":"user"}]},"privacy":{"value":""},"type":"status","created_time":"2014-10-10T18:35:16+0000","updated_time":"2014-10-10T18:35:16+0000"},{"id":"4681211244366_4676161038114","from":{"id":"4681211244366","name":"Zachy Bear Jones"},"story":"Zachy Bear Jones likes The ManKind Project.","story_tags":{"0":[{"id":"4681211244366","name":"Zachy Bear Jones","offset":0,"length":16,"type":"user"}],"23":[{"id":"95845568627","name":"The ManKind Project","offset":23,"length":19,"type":"page"}]},"picture":"https://fbcdn-profile-a.akamaihd.net/hprofile-ak-prn2/v/t1.0-1/c25.37.310.310/s100x100/47037_10151832647868628_1954427594_n.png?
Back as my JSON object. What is the next step to rendering this information as a post? In a prefect world I need profile pic, message, time, location, and the like, share, and comment actions. Any advice on how I can do this? Thank you anyone who can help!
First of all you should format your json object to a readable one to get the certain structure. Based upon your object I did this as an example:
[{
"id":"4681211244366_4681199684077",
"from":{
"id":"4681211244366",
"name":"Zachy Bear Jones"
},
"story":"Zachy Bear Jones and Alexander J. Marrs are now friends.",
"story_tags":{
"0": [{
"id":"4681211244366",
"name":"Zachy Bear Jones",
"offset":0,
"length":16,
"type":"user"
}],
"21":[{
"id":"10205311345929912",
"name":"Alexander J. Marrs",
"offset":21,
"length":18,
"type":"user"
}]
},
"actions":[{
"name":"Comment",
"link":"https://www.facebook.com/4681211244366/posts/4681199684077"
},{
"name":"Like",
"link":"https://www.facebook.com/4681211244366/posts/4681199684077"
}],
"privacy":{
"value":""
},
"type":"status",
"status_type":"approved_friend",
"created_time":"2014-10-11T21:33:29+0000",
"updated_time":"2014-10-11T21:33:29+0000"
},
...
To display data use something like this:
<div id='fb-root'>
<div ng-repeat="post in facebook">
Post from: {{post.from.name}} <br />
Story: {{post.story}} <br />
Tagged: <span ng-repeat="tag in post">{{tag.name}}</span>
</div>
</div>
This should result in something like this:
<div id='fb-root'>
<div>
Post from: Zachy Bear Jones <br />
Story: Zachy Bear Jones and Alexander J. Marrs are now friends. <br />
Tagged: <span>Zachy Bear Jones</span><span>Alexander J. Marrs</span>
</div>
</div>
I have two entities: Event and Person.
I have both gsp pages that allows me to create events and persons. In Event page, I have the possibility to select an existing person, or I can insert name, surname and phone number.
I would have a button that, if that three fields are filled, allows me to jump to create page of Person, with that three fields filled with data inserted in Event page.
I've tried with tag as follows:
<g:link controller="patient" action="create"
params="[name: eventInstance.patientName, surname: eventInstance.patientSurname,
phone_1: eventInstance.phoneNumber]">link</g:link>
but in this way parameters are empty.
Any suggestion?
EDIT:
I've tried the following:
<g:actionSubmit value="createPatient" action="createPatient"></g:actionSubmit>
and the action is:
def createPatient()
{
def eventInstance = new Event(params)
println("params are "+ params)
redirect(controller: "patient", action: "create", params: [name: "name", surname:
"surname", phone_1: "025-84569"] )
}
In this way, the Create action is performed and I see the gsp page with form prefilled with parameter passed. The fact is that params has not the values that I want to pass to create.gsp (values needed are patientName, patientSurname and phoneNumber). Infact, the println() shows me:
params are [_action_createPatient:createPatient, recurInterval:1, recurCount:,
recurType:DAILY, endTime:, recurEndOption:never, recurUntil:, startTime:, title:,
patient_textField:, healthService.id:1, healthService:[id:1], patientName:,
phoneNumber:, description:, _recurDaysOfWeek:[, , , , , , ], patientSurname:,
patient_id:, action:save, controller:event]
I am a newbie in Grails, and still learning.
I have the following code for the model:
class Book {
static constraints = {
}
String title
String author
}
and controller:
class KillController {
def index() { render "kill world" }
def view() {
def book = new Book( author: "Mike", title: "nuff sed")
[ model: book ]
}
}
And for view.gsp, I have the following:
<html>
<body>
Author: ${ model.author }<br />
Title : ${ model.title }
</body>
</html>
Everything is working, and the correct output is produced. However, in the GSP editor, when I type ${ model. }, I don't get any proposals from code-assist. Pressing ctrl+space after typing the dot does not help.
Pressing Ctrl+space inside ${ } works though, and it correctly recognizes model as a Book object.
Is code assist for models not yet supported in the GSP editor? Thanks! :D
This is a bug. It should be working and it does in many other situations. When I try it, I do see that an exception is being thrown:
org.eclipse.core.runtime.OperationCanceledException
at org.codehaus.groovy.eclipse.codeassist.processors.GroovyProposalTypeSearchRequestor.checkCancel(GroovyProposalTypeSearchRequestor.java:356)
at org.codehaus.groovy.eclipse.codeassist.processors.GroovyProposalTypeSearchRequestor.processAcceptedPackages(GroovyProposalTypeSearchRequestor.java:618)
at org.codehaus.groovy.eclipse.codeassist.processors.PackageCompletionProcessor.generateProposals(PackageCompletionProcessor.java:56)
at org.codehaus.groovy.eclipse.codeassist.requestor.GroovyCompletionProposalComputer.computeCompletionProposals(GroovyCompletionProposalComputer.java:162)
at org.grails.ide.eclipse.editor.gsp.adapter.CodeCompletionDelegate.codeComplete(CodeCompletionDelegate.java:71)
at org.codehaus.jdt.groovy.model.GroovyCompilationUnit.codeComplete(GroovyCompilationUnit.java:598)
at org.eclipse.jdt.internal.core.CompilationUnit.codeComplete(CompilationUnit.java:359)
at org.eclipse.jst.jsp.ui.internal.contentassist.JSPJavaCompletionProposalComputer.computeJavaCompletionProposals(JSPJavaCompletionProposalComputer.java:237)
at org.eclipse.jst.jsp.ui.internal.contentassist.JSPJavaCompletionProposalComputer.computeCompletionProposals(JSPJavaCompletionProposalComputer.java:114)
at org.eclipse.wst.sse.ui.internal.contentassist.CompletionProposalComputerDescriptor.computeCompletionProposals(CompletionProposalComputerDescriptor.java:284)
at org.eclipse.wst.sse.ui.internal.contentassist.CompletionProposalCategory.computeCompletionProposals(CompletionProposalCategory.java:290)
at org.eclipse.wst.sse.ui.contentassist.StructuredContentAssistProcessor.collectProposals(StructuredContentAssistProcessor.java:475)
at org.eclipse.wst.sse.ui.contentassist.StructuredContentAssistProcessor.computeCompletionProposals(StructuredContentAssistProcessor.java:254)
at org.eclipse.wst.sse.ui.internal.contentassist.CompoundContentAssistProcessor.computeCompletionProposals(CompoundContentAssistProcessor.java:127)
at org.eclipse.jface.text.contentassist.ContentAssistant.computeCompletionProposals(ContentAssistant.java:1839)
at org.eclipse.jface.text.contentassist.CompletionProposalPopup.computeProposals(CompletionProposalPopup.java:566)
at org.eclipse.jface.text.contentassist.CompletionProposalPopup.access$16(CompletionProposalPopup.java:563)
at org.eclipse.jface.text.contentassist.CompletionProposalPopup$2.run(CompletionProposalPopup.java:498)
...
I'll have to see what is going on here.
UPDATE:
Raised this issue: https://issuetracker.springsource.com/browse/STS-3337
Found the problem and pushed a fix. Will be available in next snapshot build.