From 230cce93c344e1c1d29e297975ae2960391611fe Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Thu, 11 May 2023 21:21:37 +0530 Subject: [PATCH 01/27] checkout works. Work on product selector --- static/js/src/advantage/credentials/app.tsx | 2 + .../components/CredCheckout/CredCheckout.tsx | 94 +++++++++++++++++++ .../components/CredCheckout/index.tsx | 1 + .../components/CredShop/CredShop.tsx | 2 + .../CredShop/ExamSummary/ExamSummary.tsx | 15 +++ .../components/CredShop/ExamSummary/index.tsx | 1 + templates/credentials/shop/index.html | 5 +- 7 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx create mode 100644 static/js/src/advantage/credentials/components/CredCheckout/index.tsx create mode 100644 static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx create mode 100644 static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx diff --git a/static/js/src/advantage/credentials/app.tsx b/static/js/src/advantage/credentials/app.tsx index 83c5a0c53b6..144e581654c 100644 --- a/static/js/src/advantage/credentials/app.tsx +++ b/static/js/src/advantage/credentials/app.tsx @@ -7,6 +7,7 @@ import { ReactQueryDevtools } from "react-query/devtools"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import CredManage from "./components/CredManage"; import CredShop from "./components/CredShop"; +import CredCheckout from "./components/CredCheckout"; const oneHour = 1000 * 60 * 60; const queryClient = new QueryClient({ @@ -39,6 +40,7 @@ function App() { } /> } /> + } /> diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx new file mode 100644 index 00000000000..98047bc9d18 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import { QueryClient, QueryClientProvider } from "react-query"; +import { ReactQueryDevtools } from "react-query/devtools"; +import * as Sentry from "@sentry/react"; +import { Integrations } from "@sentry/tracing"; +import { Elements } from "@stripe/react-stripe-js"; +import { loadStripe } from "@stripe/stripe-js"; +import { UserSubscriptionMarketplace } from "advantage/api/enum"; +import Checkout from "advantage/subscribe/checkout/components/Checkout"; +import { Action, LoginSession, Product } from "advantage/subscribe/checkout/utils/types"; + + +const oneHour = 1000 * 60 * 60; +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + refetchOnMount: false, + refetchOnReconnect: false, + staleTime: oneHour, + retryOnMount: false, + }, + }, +}); + +Sentry.init({ + dsn: "https://0293bb7fc3104e56bafd2422e155790c@sentry.is.canonical.com//13", + integrations: [ + new Integrations.BrowserTracing({ + tracingOrigins: ["ubuntu.com"], + }), + ], + allowUrls: ["ubuntu.com"], + tracesSampleRate: 1.0, +}); + +declare global { + interface Window { + accountId?: string; + stripePublishableKey?: string; + loginSession?: LoginSession; + marketplace: UserSubscriptionMarketplace; + canTrial?: boolean; + currentPaymentId: string; + invoiceId: string; + captcha: string | null; + previousPurchaseIds?: { monthly: string; yearly: string }; + GAFriendlyProduct?: { + id: string; + name: string; + price: number; + quantity: number; + }; + } +} +// {"product":{"id":"uaia-essential-physical-yearly","longId":"lAEv6IVik3kqgRk2zH9cxZdRR8ylyrYPXcG_13ZPEArc","name":"Ubuntu Pro","price":{"value":50000,"currency":"USD"},"period":"yearly","productID":"uaia-essential-physical","canBeTrialled":true,"private":false,"marketplace":"canonical-ua"},"quantity":1,"action":"purchase"} +// const checkoutData = localStorage.getItem("shop-checkout-data") || ""; +// const parsedCheckoutData = JSON.parse(checkoutData); +const parsedCheckoutData = { product: { id: "cue-activation-key", longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", name: "CUE Activation Key", price: { value: "4900", currency: "USD" }, period: "monthly", productID: "cue-activation-key", canBeTrialled: false, private: "false", marketplace: "canonical-ua" }, quantity: 3, action: "purchase" }; +const stripePromise = loadStripe(window.stripePublishableKey || ""); +const product: Product = parsedCheckoutData?.product; +const quantity: number = parsedCheckoutData?.quantity; +const action: Action = parsedCheckoutData?.action; +console.log(product, quantity, action); +window.previousPurchaseIds = { + monthly: "", + yearly: "", +}; +window.canTrial = undefined; +window.currentPaymentId = ""; +window.accountId = ""; +window.captcha = null; + +window.marketplace = product.marketplace; +window.GAFriendlyProduct = { + id: product?.id, + name: product?.name, + price: (product?.price?.value ?? 0) / 100, + quantity: quantity, +}; + +const CredCheckout = () => { + return ( + + + + + + + + + ); +}; +export default CredCheckout; diff --git a/static/js/src/advantage/credentials/components/CredCheckout/index.tsx b/static/js/src/advantage/credentials/components/CredCheckout/index.tsx new file mode 100644 index 00000000000..64992ae869a --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredCheckout/index.tsx @@ -0,0 +1 @@ +export { default } from "./CredCheckout"; diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index a5dfcc9b538..f1cff49b0dd 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -1,10 +1,12 @@ import React from "react"; import { Link } from "react-router-dom"; +import ExamSummary from "./ExamSummary/ExamSummary"; const CredShop = () => { return ( <>

Shop

manage + ); }; diff --git a/static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx b/static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx new file mode 100644 index 00000000000..7d1df51bc61 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx @@ -0,0 +1,15 @@ +import { Col, Row } from "@canonical/react-components"; +import React from "react"; + +const ExamSummary = () => { + return (<> +
+ + + Your Order + + +
+ ); +}; +export default ExamSummary; diff --git a/static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx b/static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx new file mode 100644 index 00000000000..5a038de35b2 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx @@ -0,0 +1 @@ +export { default } from "./ExamSummary"; diff --git a/templates/credentials/shop/index.html b/templates/credentials/shop/index.html index a62e9b37bf0..fef66dd0fb6 100644 --- a/templates/credentials/shop/index.html +++ b/templates/credentials/shop/index.html @@ -16,4 +16,7 @@ -{% endblock %} \ No newline at end of file + +{% endblock %} From 8541b4b737bb6124360fad5705a32bdc937564df Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Fri, 12 May 2023 02:09:59 +0530 Subject: [PATCH 02/27] writes product info to localstorage --- .../components/CredCheckout/CredCheckout.tsx | 127 ++++++++++-------- .../components/CredShop/CredShop.tsx | 95 ++++++++++++- .../CredShop/ExamSummary/ExamSummary.tsx | 15 --- .../components/CredShop/ExamSummary/index.tsx | 1 - 4 files changed, 161 insertions(+), 77 deletions(-) delete mode 100644 static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx delete mode 100644 static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx index 98047bc9d18..84d376770ac 100644 --- a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx +++ b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx @@ -7,64 +7,81 @@ import { Elements } from "@stripe/react-stripe-js"; import { loadStripe } from "@stripe/stripe-js"; import { UserSubscriptionMarketplace } from "advantage/api/enum"; import Checkout from "advantage/subscribe/checkout/components/Checkout"; -import { Action, LoginSession, Product } from "advantage/subscribe/checkout/utils/types"; - +import { + Action, + LoginSession, + Product, +} from "advantage/subscribe/checkout/utils/types"; const oneHour = 1000 * 60 * 60; const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - refetchOnMount: false, - refetchOnReconnect: false, - staleTime: oneHour, - retryOnMount: false, - }, + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + refetchOnMount: false, + refetchOnReconnect: false, + staleTime: oneHour, + retryOnMount: false, }, + }, }); Sentry.init({ - dsn: "https://0293bb7fc3104e56bafd2422e155790c@sentry.is.canonical.com//13", - integrations: [ - new Integrations.BrowserTracing({ - tracingOrigins: ["ubuntu.com"], - }), - ], - allowUrls: ["ubuntu.com"], - tracesSampleRate: 1.0, + dsn: "https://0293bb7fc3104e56bafd2422e155790c@sentry.is.canonical.com//13", + integrations: [ + new Integrations.BrowserTracing({ + tracingOrigins: ["ubuntu.com"], + }), + ], + allowUrls: ["ubuntu.com"], + tracesSampleRate: 1.0, }); declare global { - interface Window { - accountId?: string; - stripePublishableKey?: string; - loginSession?: LoginSession; - marketplace: UserSubscriptionMarketplace; - canTrial?: boolean; - currentPaymentId: string; - invoiceId: string; - captcha: string | null; - previousPurchaseIds?: { monthly: string; yearly: string }; - GAFriendlyProduct?: { - id: string; - name: string; - price: number; - quantity: number; - }; - } + interface Window { + accountId?: string; + stripePublishableKey?: string; + loginSession?: LoginSession; + marketplace: UserSubscriptionMarketplace; + canTrial?: boolean; + currentPaymentId: string; + invoiceId: string; + captcha: string | null; + previousPurchaseIds?: { monthly: string; yearly: string }; + GAFriendlyProduct?: { + id: string; + name: string; + price: number; + quantity: number; + }; + } } -// {"product":{"id":"uaia-essential-physical-yearly","longId":"lAEv6IVik3kqgRk2zH9cxZdRR8ylyrYPXcG_13ZPEArc","name":"Ubuntu Pro","price":{"value":50000,"currency":"USD"},"period":"yearly","productID":"uaia-essential-physical","canBeTrialled":true,"private":false,"marketplace":"canonical-ua"},"quantity":1,"action":"purchase"} -// const checkoutData = localStorage.getItem("shop-checkout-data") || ""; -// const parsedCheckoutData = JSON.parse(checkoutData); -const parsedCheckoutData = { product: { id: "cue-activation-key", longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", name: "CUE Activation Key", price: { value: "4900", currency: "USD" }, period: "monthly", productID: "cue-activation-key", canBeTrialled: false, private: "false", marketplace: "canonical-ua" }, quantity: 3, action: "purchase" }; +const checkoutData = localStorage.getItem("shop-checkout-data") || ""; +// console.log(checkoutData); +const parsedCheckoutData = JSON.parse(checkoutData); +// const parsedCheckoutData = { +// product: { +// id: "cue-activation-key", +// longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", +// name: "CUE Activation Key", +// price: { value: "4900", currency: "USD" }, +// period: "monthly", +// productID: "cue-activation-key", +// canBeTrialled: false, +// private: "false", +// marketplace: "canonical-ua", +// }, +// quantity: 3, +// action: "purchase", +// }; const stripePromise = loadStripe(window.stripePublishableKey || ""); const product: Product = parsedCheckoutData?.product; const quantity: number = parsedCheckoutData?.quantity; const action: Action = parsedCheckoutData?.action; console.log(product, quantity, action); window.previousPurchaseIds = { - monthly: "", - yearly: "", + monthly: "", + yearly: "", }; window.canTrial = undefined; window.currentPaymentId = ""; @@ -73,22 +90,22 @@ window.captcha = null; window.marketplace = product.marketplace; window.GAFriendlyProduct = { - id: product?.id, - name: product?.name, - price: (product?.price?.value ?? 0) / 100, - quantity: quantity, + id: product?.id, + name: product?.name, + price: (product?.price?.value ?? 0) / 100, + quantity: quantity, }; const CredCheckout = () => { - return ( - - - - - - - - - ); + return ( + + + + + + + + + ); }; export default CredCheckout; diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index f1cff49b0dd..94adaef500c 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -1,12 +1,95 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import ExamSummary from "./ExamSummary/ExamSummary"; +import React, { useState } from "react"; +import { Product } from "advantage/subscribe/react/utils/utils"; +import { + Button, + Col, + Form, + Input, + Row, + Strip, +} from "@canonical/react-components"; +import { currencyFormatter } from "advantage/react/utils"; + const CredShop = () => { + const CUEExamKey: Product = { + id: "cue-activation-key", + longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", + name: "CUE Activation Key", + price: { value: 4900, currency: "USD" }, + productID: "cue-activation-key", + canBeTrialled: false, + private: false, + marketplace: "canonical-ua", + }; + const [quantity, setQuantity] = useState(1); + const handleChange: React.ChangeEventHandler = (event: React.ChangeEvent) => { + event.preventDefault(); + setQuantity(event.target.value); + }; return ( <> -

Shop

- manage - + + +

How many exams attempts do you need?

+
+ + +
+ +
+ +
+ +

+ Each exam attempt allows you to register for one of the following + certifications: +

    +
  • CUE.01: Linux
  • +
  • CUE.02: Desktop
  • +
  • CUE.03: Server
  • +
+

+
+
+
+ + + Your Order + + + + {quantity} x Exam attempt key + + {currencyFormatter.format( + ((CUEExamKey?.price.value ?? 0) / 100) * (Number(quantity) ?? 0) + )} + + + + + +
); }; diff --git a/static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx b/static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx deleted file mode 100644 index 7d1df51bc61..00000000000 --- a/static/js/src/advantage/credentials/components/CredShop/ExamSummary/ExamSummary.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Col, Row } from "@canonical/react-components"; -import React from "react"; - -const ExamSummary = () => { - return (<> -
- - - Your Order - - -
- ); -}; -export default ExamSummary; diff --git a/static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx b/static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx deleted file mode 100644 index 5a038de35b2..00000000000 --- a/static/js/src/advantage/credentials/components/CredShop/ExamSummary/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ExamSummary"; From 7fc2a3bdecce0043981c3a5d8c3c80cb38f0f3fb Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Fri, 12 May 2023 02:43:04 +0530 Subject: [PATCH 03/27] read from local if set in product selector --- .../advantage/credentials/components/CredShop/CredShop.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index 94adaef500c..313053a4b74 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -11,7 +11,7 @@ import { import { currencyFormatter } from "advantage/react/utils"; const CredShop = () => { - const CUEExamKey: Product = { + const CUEExamKey = { id: "cue-activation-key", longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", name: "CUE Activation Key", @@ -21,7 +21,10 @@ const CredShop = () => { private: false, marketplace: "canonical-ua", }; - const [quantity, setQuantity] = useState(1); + const checkoutData = localStorage.getItem("shop-checkout-data") || ""; + const parsedCheckoutData = JSON.parse(checkoutData); + const initQuantity: number = parsedCheckoutData?.quantity; + const [quantity, setQuantity] = useState(initQuantity ?? 1); const handleChange: React.ChangeEventHandler = (event: React.ChangeEvent) => { event.preventDefault(); setQuantity(event.target.value); From af744b6be64ca81c977aeb7d9e09d3337cb0d4ac Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Fri, 12 May 2023 02:47:20 +0530 Subject: [PATCH 04/27] remove unused stuff --- .../components/CredCheckout/CredCheckout.tsx | 16 ---------------- .../credentials/components/CredShop/CredShop.tsx | 1 - 2 files changed, 17 deletions(-) diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx index 84d376770ac..ac18bc7f75c 100644 --- a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx +++ b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx @@ -57,23 +57,7 @@ declare global { } } const checkoutData = localStorage.getItem("shop-checkout-data") || ""; -// console.log(checkoutData); const parsedCheckoutData = JSON.parse(checkoutData); -// const parsedCheckoutData = { -// product: { -// id: "cue-activation-key", -// longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", -// name: "CUE Activation Key", -// price: { value: "4900", currency: "USD" }, -// period: "monthly", -// productID: "cue-activation-key", -// canBeTrialled: false, -// private: "false", -// marketplace: "canonical-ua", -// }, -// quantity: 3, -// action: "purchase", -// }; const stripePromise = loadStripe(window.stripePublishableKey || ""); const product: Product = parsedCheckoutData?.product; const quantity: number = parsedCheckoutData?.quantity; diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index 313053a4b74..149acc5671f 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -1,5 +1,4 @@ import React, { useState } from "react"; -import { Product } from "advantage/subscribe/react/utils/utils"; import { Button, Col, From 43ec9b2684d1c9f266856ead247512cac37572fb Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Fri, 12 May 2023 17:42:32 +0530 Subject: [PATCH 05/27] Redirect works --- .../components/CredCheckout/CredCheckout.tsx | 7 ++++++- static/js/src/advantage/subscribe/checkout/app.tsx | 7 ++++++- .../checkout/components/BuyButton/BuyButton.tsx | 11 +++++++++-- .../checkout/components/Checkout/Checkout.tsx | 4 +++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx index ac18bc7f75c..7ec1c0e45f1 100644 --- a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx +++ b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx @@ -85,7 +85,12 @@ const CredCheckout = () => { - + diff --git a/static/js/src/advantage/subscribe/checkout/app.tsx b/static/js/src/advantage/subscribe/checkout/app.tsx index 5cae699497b..837b4456c2a 100644 --- a/static/js/src/advantage/subscribe/checkout/app.tsx +++ b/static/js/src/advantage/subscribe/checkout/app.tsx @@ -83,7 +83,12 @@ const App = () => { - + diff --git a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx index 8a07b2d4f14..f93040e6688 100644 --- a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx +++ b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx @@ -18,9 +18,16 @@ type Props = { quantity: number; product: Product; action: Action; + redirectURL: string; }; -const BuyButton = ({ setError, quantity, product, action }: Props) => { +const BuyButton = ({ + setError, + quantity, + product, + action, + redirectURL, +}: Props) => { const [isLoading, setIsLoading] = useState(false); const { @@ -325,7 +332,7 @@ const BuyButton = ({ setError, quantity, product, action }: Props) => { email )}`; } else { - location.pathname = "/pro/dashboard"; + location.pathname = redirectURL; } } }; diff --git a/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx b/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx index 40f1b5bac38..c15ded9ecdf 100644 --- a/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx +++ b/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx @@ -23,9 +23,10 @@ type Props = { product: Product; quantity: number; action: Action; + redirectURL: string; }; -const Checkout = ({ product, quantity, action }: Props) => { +const Checkout = ({ product, quantity, action, redirectURL }: Props) => { const [error, setError] = useState(null); const { data: userInfo, isLoading: isUserInfoLoading } = useCustomerInfo(); const isGuest = !userInfo?.customerInfo?.email; @@ -139,6 +140,7 @@ const Checkout = ({ product, quantity, action }: Props) => { quantity={quantity} action={action} setError={setError} + redirectURL={redirectURL} > From 9d079b4edf5ac75514b89d25ff601a8957dd89a8 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Sat, 13 May 2023 01:39:33 +0530 Subject: [PATCH 06/27] thank you page added along with bugfixes --- static/js/src/advantage/credentials/app.tsx | 5 ++ .../components/CredCheckout/CredCheckout.tsx | 6 +- .../CredPurchaseConfirmation.tsx | 59 +++++++++++++++++++ .../CredPurchaseConfirmation/index.tsx | 1 + .../components/CredShop/CredShop.tsx | 3 +- 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx create mode 100644 static/js/src/advantage/credentials/components/CredPurchaseConfirmation/index.tsx diff --git a/static/js/src/advantage/credentials/app.tsx b/static/js/src/advantage/credentials/app.tsx index 144e581654c..8518816a3ce 100644 --- a/static/js/src/advantage/credentials/app.tsx +++ b/static/js/src/advantage/credentials/app.tsx @@ -8,6 +8,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import CredManage from "./components/CredManage"; import CredShop from "./components/CredShop"; import CredCheckout from "./components/CredCheckout"; +import CredPurchaseConfirmation from "./components/CredPurchaseConfirmation/CredPurchaseConfirmation"; const oneHour = 1000 * 60 * 60; const queryClient = new QueryClient({ @@ -41,6 +42,10 @@ function App() { } /> } /> } /> + } + /> diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx index 7ec1c0e45f1..d0108bda25b 100644 --- a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx +++ b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx @@ -56,7 +56,7 @@ declare global { }; } } -const checkoutData = localStorage.getItem("shop-checkout-data") || ""; +const checkoutData = localStorage.getItem("shop-checkout-data") || "{}"; const parsedCheckoutData = JSON.parse(checkoutData); const stripePromise = loadStripe(window.stripePublishableKey || ""); const product: Product = parsedCheckoutData?.product; @@ -72,7 +72,7 @@ window.currentPaymentId = ""; window.accountId = ""; window.captcha = null; -window.marketplace = product.marketplace; +window.marketplace = product?.marketplace; window.GAFriendlyProduct = { id: product?.id, name: product?.name, @@ -89,7 +89,7 @@ const CredCheckout = () => { product={product} quantity={quantity} action={action} - redirectURL="/credentials/your-exams" + redirectURL={`/credentials/shop/order-thank-you?productName=${product.name}&quantity=${quantity}`} /> diff --git a/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx b/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx new file mode 100644 index 00000000000..ffcf4341714 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx @@ -0,0 +1,59 @@ +import { Button, Col, Row } from "@canonical/react-components"; +import React from "react"; +import { Link, useSearchParams } from "react-router-dom"; + +const CredPurchaseConfirmation = () => { + const [queryParameters] = useSearchParams(); + const quantity = queryParameters.get("quantity"); + const product = queryParameters.get("productName"); + return ( +
+ +

Thank You for your order!

+

+ {quantity} x {product} +

+

How to use an activation key to redeem exam attempts

+
+ + +

Log in to /credentials/activate

+

+ Enter your key on /credentials/activate to redeem your exam attempt. + After activation, you will be able to take your exam right away or + schedule it for another day. +

+ + + +

Manage Your Keys

+

+ Want to see exam attempt codes you already purchased? Go to + /credentials/manage-exam-attempts. +

+ + + +

Manage Your Exams

+

+ Need to schedule or re-schedule an exam? Go to + /credentials/your-exams. +

+ + + + +
+ +

+ Consult our FAQ for further questions, or contact us at{" "} + + credentials@canonical.com + + . +

+
+
+ ); +}; +export default CredPurchaseConfirmation; diff --git a/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/index.tsx b/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/index.tsx new file mode 100644 index 00000000000..fb0cb3b60a5 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/index.tsx @@ -0,0 +1 @@ +export { default } from "./CredPurchaseConfirmation"; diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index 149acc5671f..485fff9cb7b 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -20,7 +20,7 @@ const CredShop = () => { private: false, marketplace: "canonical-ua", }; - const checkoutData = localStorage.getItem("shop-checkout-data") || ""; + const checkoutData = localStorage.getItem("shop-checkout-data") || "{}"; const parsedCheckoutData = JSON.parse(checkoutData); const initQuantity: number = parsedCheckoutData?.quantity; const [quantity, setQuantity] = useState(initQuantity ?? 1); @@ -40,6 +40,7 @@ const CredShop = () => { From 3b6ac90c5a964a8d72bc0f32b566688296811233 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Fri, 19 May 2023 18:03:37 +0530 Subject: [PATCH 07/27] fixed failing redirect on checkout --- .../credentials/components/CredCheckout/CredCheckout.tsx | 4 +++- .../subscribe/checkout/components/BuyButton/BuyButton.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx index d0108bda25b..7aaa52e346c 100644 --- a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx +++ b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx @@ -89,7 +89,9 @@ const CredCheckout = () => { product={product} quantity={quantity} action={action} - redirectURL={`/credentials/shop/order-thank-you?productName=${product.name}&quantity=${quantity}`} + redirectURL={`/credentials/shop/order-thank-you?productName=${encodeURIComponent( + product.name + )}&quantity=${encodeURIComponent(quantity)}`} /> diff --git a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx index f93040e6688..18e23f82b32 100644 --- a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx +++ b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx @@ -332,7 +332,7 @@ const BuyButton = ({ email )}`; } else { - location.pathname = redirectURL; + location.href = redirectURL; } } }; From 5d55ac1e372e2002bf3c662fc7782e0e3eb6b5b9 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Fri, 19 May 2023 18:08:57 +0530 Subject: [PATCH 08/27] change marketplace for activation keys --- .../src/advantage/credentials/components/CredShop/CredShop.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index 485fff9cb7b..7681f53b1b2 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -18,7 +18,7 @@ const CredShop = () => { productID: "cue-activation-key", canBeTrialled: false, private: false, - marketplace: "canonical-ua", + marketplace: "canonical-cube", }; const checkoutData = localStorage.getItem("shop-checkout-data") || "{}"; const parsedCheckoutData = JSON.parse(checkoutData); From 9b1b78d6619b882ae9fdc5b79717340bf0293a04 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Tue, 23 May 2023 20:57:52 +0530 Subject: [PATCH 09/27] Removed duplicate code --- static/js/src/advantage/credentials/app.tsx | 2 - .../components/CredCheckout/CredCheckout.tsx | 102 ------------------ .../components/CredCheckout/index.tsx | 1 - .../components/CredShop/CredShop.tsx | 2 +- .../src/advantage/subscribe/checkout/app.tsx | 1 - .../components/BuyButton/BuyButton.tsx | 20 ++-- .../checkout/components/Checkout/Checkout.tsx | 4 +- 7 files changed, 10 insertions(+), 122 deletions(-) delete mode 100644 static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx delete mode 100644 static/js/src/advantage/credentials/components/CredCheckout/index.tsx diff --git a/static/js/src/advantage/credentials/app.tsx b/static/js/src/advantage/credentials/app.tsx index 8518816a3ce..33825063ade 100644 --- a/static/js/src/advantage/credentials/app.tsx +++ b/static/js/src/advantage/credentials/app.tsx @@ -7,7 +7,6 @@ import { ReactQueryDevtools } from "react-query/devtools"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import CredManage from "./components/CredManage"; import CredShop from "./components/CredShop"; -import CredCheckout from "./components/CredCheckout"; import CredPurchaseConfirmation from "./components/CredPurchaseConfirmation/CredPurchaseConfirmation"; const oneHour = 1000 * 60 * 60; @@ -41,7 +40,6 @@ function App() { } /> } /> - } /> } diff --git a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx b/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx deleted file mode 100644 index 7aaa52e346c..00000000000 --- a/static/js/src/advantage/credentials/components/CredCheckout/CredCheckout.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import React from "react"; -import { QueryClient, QueryClientProvider } from "react-query"; -import { ReactQueryDevtools } from "react-query/devtools"; -import * as Sentry from "@sentry/react"; -import { Integrations } from "@sentry/tracing"; -import { Elements } from "@stripe/react-stripe-js"; -import { loadStripe } from "@stripe/stripe-js"; -import { UserSubscriptionMarketplace } from "advantage/api/enum"; -import Checkout from "advantage/subscribe/checkout/components/Checkout"; -import { - Action, - LoginSession, - Product, -} from "advantage/subscribe/checkout/utils/types"; - -const oneHour = 1000 * 60 * 60; -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - refetchOnMount: false, - refetchOnReconnect: false, - staleTime: oneHour, - retryOnMount: false, - }, - }, -}); - -Sentry.init({ - dsn: "https://0293bb7fc3104e56bafd2422e155790c@sentry.is.canonical.com//13", - integrations: [ - new Integrations.BrowserTracing({ - tracingOrigins: ["ubuntu.com"], - }), - ], - allowUrls: ["ubuntu.com"], - tracesSampleRate: 1.0, -}); - -declare global { - interface Window { - accountId?: string; - stripePublishableKey?: string; - loginSession?: LoginSession; - marketplace: UserSubscriptionMarketplace; - canTrial?: boolean; - currentPaymentId: string; - invoiceId: string; - captcha: string | null; - previousPurchaseIds?: { monthly: string; yearly: string }; - GAFriendlyProduct?: { - id: string; - name: string; - price: number; - quantity: number; - }; - } -} -const checkoutData = localStorage.getItem("shop-checkout-data") || "{}"; -const parsedCheckoutData = JSON.parse(checkoutData); -const stripePromise = loadStripe(window.stripePublishableKey || ""); -const product: Product = parsedCheckoutData?.product; -const quantity: number = parsedCheckoutData?.quantity; -const action: Action = parsedCheckoutData?.action; -console.log(product, quantity, action); -window.previousPurchaseIds = { - monthly: "", - yearly: "", -}; -window.canTrial = undefined; -window.currentPaymentId = ""; -window.accountId = ""; -window.captcha = null; - -window.marketplace = product?.marketplace; -window.GAFriendlyProduct = { - id: product?.id, - name: product?.name, - price: (product?.price?.value ?? 0) / 100, - quantity: quantity, -}; - -const CredCheckout = () => { - return ( - - - - - - - - - ); -}; -export default CredCheckout; diff --git a/static/js/src/advantage/credentials/components/CredCheckout/index.tsx b/static/js/src/advantage/credentials/components/CredCheckout/index.tsx deleted file mode 100644 index 64992ae869a..00000000000 --- a/static/js/src/advantage/credentials/components/CredCheckout/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CredCheckout"; diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index 7681f53b1b2..f6aae8a4a59 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -85,7 +85,7 @@ const CredShop = () => { action: "purchase", }) ); - location.href = "/credentials/shop/checkout"; + location.href = "/account/checkout"; }} > Buy Now diff --git a/static/js/src/advantage/subscribe/checkout/app.tsx b/static/js/src/advantage/subscribe/checkout/app.tsx index 837b4456c2a..a9a9dc99b46 100644 --- a/static/js/src/advantage/subscribe/checkout/app.tsx +++ b/static/js/src/advantage/subscribe/checkout/app.tsx @@ -87,7 +87,6 @@ const App = () => { product={product} quantity={quantity} action={action} - redirectURL="/pro/dashboard" /> diff --git a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx index 18e23f82b32..dd0b560b44a 100644 --- a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx +++ b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx @@ -18,16 +18,9 @@ type Props = { quantity: number; product: Product; action: Action; - redirectURL: string; }; -const BuyButton = ({ - setError, - quantity, - product, - action, - redirectURL, -}: Props) => { +const BuyButton = ({ setError, quantity, product, action }: Props) => { const [isLoading, setIsLoading] = useState(false); const { @@ -320,19 +313,22 @@ const BuyButton = ({ request.onreadystatechange = () => { if (request.readyState === 4) { localStorage.removeItem("shop-checkout-data"); - if (!window.loginSession) { + if (product.marketplace == "canonical-cube") { + console.log("Reaches here 1"); + location.href = `/credentials/shop/order-thank-you?productName=${encodeURIComponent( + product.name + )}&quantity=${quantity}`; + } else if (!window.loginSession) { const email = userInfo?.customerInfo?.email || values.email || ""; - let urlBase = "/pro/subscribe"; if (product.marketplace == "blender") { urlBase = "/pro/subscribe/blender"; } - location.href = `${urlBase}/thank-you?email=${encodeURIComponent( email )}`; } else { - location.href = redirectURL; + location.href = "/pro/dashboard"; } } }; diff --git a/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx b/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx index c15ded9ecdf..40f1b5bac38 100644 --- a/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx +++ b/static/js/src/advantage/subscribe/checkout/components/Checkout/Checkout.tsx @@ -23,10 +23,9 @@ type Props = { product: Product; quantity: number; action: Action; - redirectURL: string; }; -const Checkout = ({ product, quantity, action, redirectURL }: Props) => { +const Checkout = ({ product, quantity, action }: Props) => { const [error, setError] = useState(null); const { data: userInfo, isLoading: isUserInfoLoading } = useCustomerInfo(); const isGuest = !userInfo?.customerInfo?.email; @@ -140,7 +139,6 @@ const Checkout = ({ product, quantity, action, redirectURL }: Props) => { quantity={quantity} action={action} setError={setError} - redirectURL={redirectURL} > From 70f6ee2b064464bc6ee200e26a4bda2df5978cc0 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Wed, 24 May 2023 01:27:42 +0530 Subject: [PATCH 10/27] changes requested by Morgan and Adri --- .../CredPurchaseConfirmation/CredPurchaseConfirmation.tsx | 6 +++--- .../advantage/credentials/components/CredShop/CredShop.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx b/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx index ffcf4341714..ca90911cef0 100644 --- a/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx +++ b/static/js/src/advantage/credentials/components/CredPurchaseConfirmation/CredPurchaseConfirmation.tsx @@ -17,13 +17,13 @@ const CredPurchaseConfirmation = () => { -

Log in to /credentials/activate

+

Log in to /credentials/redeem

- Enter your key on /credentials/activate to redeem your exam attempt. + Enter your key on /credentials/redeem to redeem your exam attempt. After activation, you will be able to take your exam right away or schedule it for another day.

- +

Manage Your Keys

diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index f6aae8a4a59..117058d4b0a 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -49,8 +49,8 @@ const CredShop = () => {

- Each exam attempt allows you to register for one of the following - certifications: + Each exam attempt allows you to register for one or more of the + following certifications:

  • CUE.01: Linux
  • CUE.02: Desktop
  • From 0bd2bee64f4ca0fb54b1a72ae9cd6dfc48b54feb Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Wed, 24 May 2023 18:24:32 +0530 Subject: [PATCH 11/27] prettier now --- static/js/src/advantage/subscribe/checkout/app.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/static/js/src/advantage/subscribe/checkout/app.tsx b/static/js/src/advantage/subscribe/checkout/app.tsx index a9a9dc99b46..5cae699497b 100644 --- a/static/js/src/advantage/subscribe/checkout/app.tsx +++ b/static/js/src/advantage/subscribe/checkout/app.tsx @@ -83,11 +83,7 @@ const App = () => { - + From fab4a5a093ca9d7593342fb6da5f379bd3299589 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Thu, 25 May 2023 20:16:01 +0530 Subject: [PATCH 12/27] fix linting issue and remove console logs --- .../advantage/credentials/components/CredShop/CredShop.tsx | 6 ++++-- .../subscribe/checkout/components/BuyButton/BuyButton.tsx | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx index 117058d4b0a..fbeead84d53 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx @@ -24,9 +24,11 @@ const CredShop = () => { const parsedCheckoutData = JSON.parse(checkoutData); const initQuantity: number = parsedCheckoutData?.quantity; const [quantity, setQuantity] = useState(initQuantity ?? 1); - const handleChange: React.ChangeEventHandler = (event: React.ChangeEvent) => { + const handleChange: React.ChangeEventHandler = ( + event: React.ChangeEvent + ) => { event.preventDefault(); - setQuantity(event.target.value); + setQuantity(parseInt(event.target.value)); }; return ( <> diff --git a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx index dd0b560b44a..3e3b8b3d198 100644 --- a/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx +++ b/static/js/src/advantage/subscribe/checkout/components/BuyButton/BuyButton.tsx @@ -314,7 +314,6 @@ const BuyButton = ({ setError, quantity, product, action }: Props) => { if (request.readyState === 4) { localStorage.removeItem("shop-checkout-data"); if (product.marketplace == "canonical-cube") { - console.log("Reaches here 1"); location.href = `/credentials/shop/order-thank-you?productName=${encodeURIComponent( product.name )}&quantity=${quantity}`; From 40ff45772dc71839e3889eed535d3c2395365333 Mon Sep 17 00:00:00 2001 From: abhigyanghosh30 Date: Thu, 1 Jun 2023 03:53:54 +0530 Subject: [PATCH 13/27] updating the product selector for the new flow --- static/js/src/advantage/credentials/app.tsx | 6 +- .../components/CredExamShop/CredExamShop.tsx | 127 ++++++++++++++++++ .../components/CredExamShop/index.tsx | 1 + .../CredKeyShop.tsx} | 4 +- .../components/CredKeyShop/index.tsx | 1 + .../credentials/components/CredShop/index.tsx | 1 - templates/credentials/shop/index.html | 10 +- 7 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 static/js/src/advantage/credentials/components/CredExamShop/CredExamShop.tsx create mode 100644 static/js/src/advantage/credentials/components/CredExamShop/index.tsx rename static/js/src/advantage/credentials/components/{CredShop/CredShop.tsx => CredKeyShop/CredKeyShop.tsx} (98%) create mode 100644 static/js/src/advantage/credentials/components/CredKeyShop/index.tsx delete mode 100644 static/js/src/advantage/credentials/components/CredShop/index.tsx diff --git a/static/js/src/advantage/credentials/app.tsx b/static/js/src/advantage/credentials/app.tsx index 33825063ade..e5a82f18e36 100644 --- a/static/js/src/advantage/credentials/app.tsx +++ b/static/js/src/advantage/credentials/app.tsx @@ -6,8 +6,9 @@ import { Integrations } from "@sentry/tracing"; import { ReactQueryDevtools } from "react-query/devtools"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import CredManage from "./components/CredManage"; -import CredShop from "./components/CredShop"; +import CredKeyShop from "./components/CredKeyShop"; import CredPurchaseConfirmation from "./components/CredPurchaseConfirmation/CredPurchaseConfirmation"; +import CredExamShop from "./components/CredExamShop/CredExamShop"; const oneHour = 1000 * 60 * 60; const queryClient = new QueryClient({ @@ -38,7 +39,8 @@ function App() { - } /> + } /> + } /> } /> { + const ExamProducts = [ + { + id: "cue-01-linux-quickcert", + longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", + name: "CUE.01 Linux QuickCert", + price: { value: 4900, currency: "USD" }, + productID: "cue-01-linux", + canBeTrialled: false, + private: false, + marketplace: "canonical-cube", + metadata: [ + { + key: "description", + value: + "Prove your basic operational knowledge of Linux by demonstrating your ability to secure, operate and maintain basic system resources. Topics include user and group management, file and filesystem navigation, and logs and installation tasks related to system maintenance.", + }, + ], + }, + { + id: "cue-02-desktop", + longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", + name: "CUE.02 Desktop QuickCert", + price: { value: 4900, currency: "USD" }, + productID: "cue-02-desktop", + canBeTrialled: false, + private: true, + marketplace: "canonical-cube", + metadata: [ + { + key: "description", + value: + "Demonstrate your knowledge of Ubuntu Desktop administrative essentials. Topics include package management, system installation, data gathering, and managing printing and displays.", + }, + ], + }, + { + id: "cue-03-server", + longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", + name: "CUE.03 Server QuickCert", + price: { value: 4900, currency: "USD" }, + productID: "cue-03-server", + canBeTrialled: false, + private: true, + marketplace: "canonical-cube", + metadata: [ + { + key: "description", + value: + "Illustrate your knowledge of common Ubuntu Server administrative tasks and troubleshooting. Topics include job control, performance tuning, services management, and Bash scripting.", + }, + ], + }, + ]; + const [exam, setExam] = useState(0); + const handleChange = (event: React.ChangeEvent) => { + setExam(parseInt(event.target.value)); + localStorage.setItem("exam-selector", JSON.stringify(event?.target.value)); + }; + + return ( + + +

    Select an exam to purchase

    +
    + + {ExamProducts.map((examElement, examIndex) => { + return ( + +
    + +
    + + ); + })} +
    +
    + ); +}; +export default CredExamShop; diff --git a/static/js/src/advantage/credentials/components/CredExamShop/index.tsx b/static/js/src/advantage/credentials/components/CredExamShop/index.tsx new file mode 100644 index 00000000000..5a773316687 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredExamShop/index.tsx @@ -0,0 +1 @@ +export { default } from "./CredExamShop"; diff --git a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx b/static/js/src/advantage/credentials/components/CredKeyShop/CredKeyShop.tsx similarity index 98% rename from static/js/src/advantage/credentials/components/CredShop/CredShop.tsx rename to static/js/src/advantage/credentials/components/CredKeyShop/CredKeyShop.tsx index fbeead84d53..339b44661ff 100644 --- a/static/js/src/advantage/credentials/components/CredShop/CredShop.tsx +++ b/static/js/src/advantage/credentials/components/CredKeyShop/CredKeyShop.tsx @@ -9,7 +9,7 @@ import { } from "@canonical/react-components"; import { currencyFormatter } from "advantage/react/utils"; -const CredShop = () => { +const CredKeyShop = () => { const CUEExamKey = { id: "cue-activation-key", longId: "lAMGrt4buzUR0-faJqg-Ot6dgNLn7ubIpWiyDgOrsDCg", @@ -98,4 +98,4 @@ const CredShop = () => { ); }; -export default CredShop; +export default CredKeyShop; diff --git a/static/js/src/advantage/credentials/components/CredKeyShop/index.tsx b/static/js/src/advantage/credentials/components/CredKeyShop/index.tsx new file mode 100644 index 00000000000..3078e460992 --- /dev/null +++ b/static/js/src/advantage/credentials/components/CredKeyShop/index.tsx @@ -0,0 +1 @@ +export { default } from "./CredKeyShop"; diff --git a/static/js/src/advantage/credentials/components/CredShop/index.tsx b/static/js/src/advantage/credentials/components/CredShop/index.tsx deleted file mode 100644 index 3040f99871a..00000000000 --- a/static/js/src/advantage/credentials/components/CredShop/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CredShop"; diff --git a/templates/credentials/shop/index.html b/templates/credentials/shop/index.html index fef66dd0fb6..adb8458d75f 100644 --- a/templates/credentials/shop/index.html +++ b/templates/credentials/shop/index.html @@ -6,14 +6,12 @@ Ubuntu Desktop, and Ubuntu Server topics.{% endblock meta_description %} {% block content %} -
    -
    -
    -
    Loading… -
    +
    +
    +
    Loading…
    -
    +