diff --git a/app/pages/externallinks/index.vue b/app/pages/externallinks/index.vue
index f50a4cf..54d8af6 100644
--- a/app/pages/externallinks/index.vue
+++ b/app/pages/externallinks/index.vue
@@ -1,19 +1,18 @@
-
+
diff --git a/public/stripe/checkout.css b/public/stripe/checkout.css
new file mode 100644
index 0000000..2147f77
--- /dev/null
+++ b/public/stripe/checkout.css
@@ -0,0 +1,242 @@
+/* Variables */
+* {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
+ font-size: 16px;
+ -webkit-font-smoothing: antialiased;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-content: center;
+ height: 100vh;
+ width: 100vw;
+}
+
+form {
+ width: 30vw;
+ min-width: 500px;
+ align-self: center;
+ box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1),
+ 0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07);
+ border-radius: 7px;
+ padding: 40px;
+ margin-top: auto;
+ margin-bottom: auto;
+}
+
+.hidden {
+ display: none;
+}
+
+#payment-message {
+ color: rgb(105, 115, 134);
+ font-size: 16px;
+ line-height: 20px;
+ padding-top: 12px;
+ text-align: center;
+}
+
+#payment-element {
+ margin-bottom: 24px;
+}
+
+/* Buttons and links */
+button {
+ background: #0055DE;
+ font-family: Arial, sans-serif;
+ color: #ffffff;
+ border-radius: 4px;
+ border: 0;
+ padding: 12px 16px;
+ font-size: 16px;
+ font-weight: 600;
+ cursor: pointer;
+ display: block;
+ transition: all 0.2s ease;
+ box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07);
+ width: 100%;
+}
+button:hover {
+ filter: contrast(115%);
+}
+button:disabled {
+ opacity: 0.5;
+ cursor: default;
+}
+
+/* spinner/processing state, errors */
+.spinner,
+.spinner:before,
+.spinner:after {
+ border-radius: 50%;
+}
+.spinner {
+ color: #ffffff;
+ font-size: 22px;
+ text-indent: -99999px;
+ margin: 0px auto;
+ position: relative;
+ width: 20px;
+ height: 20px;
+ box-shadow: inset 0 0 0 2px;
+ -webkit-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ transform: translateZ(0);
+}
+.spinner:before,
+.spinner:after {
+ position: absolute;
+ content: "";
+}
+.spinner:before {
+ width: 10.4px;
+ height: 20.4px;
+ background: #0055DE;
+ border-radius: 20.4px 0 0 20.4px;
+ top: -0.2px;
+ left: -0.2px;
+ -webkit-transform-origin: 10.4px 10.2px;
+ transform-origin: 10.4px 10.2px;
+ -webkit-animation: loading 2s infinite ease 1.5s;
+ animation: loading 2s infinite ease 1.5s;
+}
+.spinner:after {
+ width: 10.4px;
+ height: 10.2px;
+ background: #0055DE;
+ border-radius: 0 10.2px 10.2px 0;
+ top: -0.1px;
+ left: 10.2px;
+ -webkit-transform-origin: 0px 10.2px;
+ transform-origin: 0px 10.2px;
+ -webkit-animation: loading 2s infinite ease;
+ animation: loading 2s infinite ease;
+}
+
+/* Payment status page */
+#payment-status {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ row-gap: 30px;
+ width: 30vw;
+ min-width: 500px;
+ min-height: 380px;
+ align-self: center;
+ box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1),
+ 0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07);
+ border-radius: 7px;
+ padding: 40px;
+ opacity: 0;
+ animation: fadeInAnimation 1s ease forwards;
+}
+
+#status-icon {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 40px;
+ width: 40px;
+ border-radius: 50%;
+}
+
+h2 {
+ margin: 0;
+ color: #30313D;
+ text-align: center;
+}
+
+a {
+ text-decoration: none;
+ font-size: 16px;
+ font-weight: 600;
+ font-family: Arial, sans-serif;
+ display: block;
+}
+a:hover {
+ filter: contrast(120%);
+}
+
+#details-table {
+ overflow-x: auto;
+ width: 100%;
+}
+
+table {
+ width: 100%;
+ font-size: 14px;
+ border-collapse: collapse;
+}
+table tbody tr:first-child td {
+ border-top: 1px solid #E6E6E6; /* Top border */
+ padding-top: 10px;
+}
+table tbody tr:last-child td {
+ border-bottom: 1px solid #E6E6E6; /* Bottom border */
+}
+td {
+ padding-bottom: 10px;
+}
+
+.TableContent {
+ text-align: right;
+ color: #6D6E78;
+}
+
+.TableLabel {
+ font-weight: 600;
+ color: #30313D;
+}
+
+#view-details {
+ color: #0055DE;
+}
+
+#retry-button {
+ text-align: center;
+ background: #0055DE;
+ color: #ffffff;
+ border-radius: 4px;
+ border: 0;
+ padding: 12px 16px;
+ transition: all 0.2s ease;
+ box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07);
+ width: 100%;
+}
+
+@-webkit-keyframes loading {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+@keyframes loading {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+@keyframes fadeInAnimation {
+ to {
+ opacity: 1;
+ }
+}
+
+@media only screen and (max-width: 600px) {
+ form, #payment-status{
+ width: 80vw;
+ min-width: initial;
+ }
+}
\ No newline at end of file
diff --git a/public/stripe/checkout.html b/public/stripe/checkout.html
new file mode 100644
index 0000000..5f8edca
--- /dev/null
+++ b/public/stripe/checkout.html
@@ -0,0 +1,25 @@
+
+
+
+
+ Accept a payment
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/stripe/checkout.js b/public/stripe/checkout.js
new file mode 100644
index 0000000..7186169
--- /dev/null
+++ b/public/stripe/checkout.js
@@ -0,0 +1,89 @@
+// This is your test publishable API key.
+const stripe = Stripe("pk_test_51QfbSAAB1Vm8VfJq3AWsR4k2mZjnlF7XFrmlbc6XVXrtwXquAUfwzZmOFDbxMIAwqJBgqao8KLt2wmPc4vNOCTeo00WB78KtfV");
+
+// The items the customer wants to buy
+const items = [{ id: "xl-tshirt", amount: 1000 }];
+
+let elements;
+
+initialize();
+
+document
+ .querySelector("#payment-form")
+ .addEventListener("submit", handleSubmit);
+
+// Fetches a payment intent and captures the client secret
+async function initialize() {
+ // const response = await fetch("/create-payment-intent", {
+ // method: "POST",
+ // headers: { "Content-Type": "application/json" },
+ // body: JSON.stringify({ items }),
+ // });
+ // const { clientSecret } = await response.json();
+const clientSecret='pi_3QxII1AB1Vm8VfJq1OyR3bkz_secret_d8fgL53X6T3MQpYfi2lRH3V1F'
+ const appearance = {
+ theme: 'stripe',
+ };
+ elements = stripe.elements({ appearance, clientSecret });
+
+ const paymentElementOptions = {
+ layout: "accordion",
+ };
+
+ const paymentElement = elements.create("payment", paymentElementOptions);
+ paymentElement.mount("#payment-element");
+}
+
+async function handleSubmit(e) {
+ e.preventDefault();
+ setLoading(true);
+
+ const { error } = await stripe.confirmPayment({
+ elements,
+ confirmParams: {
+ // Make sure to change this to your payment completion page
+ return_url: "http://localhost:4242/complete.html",
+ },
+ });
+
+ // This point will only be reached if there is an immediate error when
+ // confirming the payment. Otherwise, your customer will be redirected to
+ // your `return_url`. For some payment methods like iDEAL, your customer will
+ // be redirected to an intermediate site first to authorize the payment, then
+ // redirected to the `return_url`.
+ if (error.type === "card_error" || error.type === "validation_error") {
+ showMessage(error.message);
+ } else {
+ showMessage("An unexpected error occurred.");
+ }
+
+ setLoading(false);
+}
+
+// ------- UI helpers -------
+
+function showMessage(messageText) {
+ const messageContainer = document.querySelector("#payment-message");
+
+ messageContainer.classList.remove("hidden");
+ messageContainer.textContent = messageText;
+
+ setTimeout(function () {
+ messageContainer.classList.add("hidden");
+ messageContainer.textContent = "";
+ }, 4000);
+}
+
+// Show a spinner on payment submission
+function setLoading(isLoading) {
+ if (isLoading) {
+ // Disable the button and show a spinner
+ document.querySelector("#submit").disabled = true;
+ document.querySelector("#spinner").classList.remove("hidden");
+ document.querySelector("#button-text").classList.add("hidden");
+ } else {
+ document.querySelector("#submit").disabled = false;
+ document.querySelector("#spinner").classList.add("hidden");
+ document.querySelector("#button-text").classList.remove("hidden");
+ }
+}
\ No newline at end of file
diff --git a/public/stripe/complete.html b/public/stripe/complete.html
new file mode 100644
index 0000000..c563264
--- /dev/null
+++ b/public/stripe/complete.html
@@ -0,0 +1,36 @@
+
+
+
+
+ Order Status
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/stripe/complete.js b/public/stripe/complete.js
new file mode 100644
index 0000000..1470ead
--- /dev/null
+++ b/public/stripe/complete.js
@@ -0,0 +1,85 @@
+// ------- UI Resources -------
+const SuccessIcon =
+``;
+
+const ErrorIcon =
+``;
+
+const InfoIcon =
+``;
+
+// ------- UI helpers -------
+function setPaymentDetails(intent) {
+ let statusText = "Something went wrong, please try again.";
+ let iconColor = "#DF1B41";
+ let icon = ErrorIcon;
+
+
+ if (!intent) {
+ setErrorState();
+ return;
+ }
+
+ switch (intent.status) {
+ case "succeeded":
+ statusText = "Payment succeeded";
+ iconColor = "#30B130";
+ icon = SuccessIcon;
+ break;
+ case "processing":
+ statusText = "Your payment is processing.";
+ iconColor = "#6D6E78";
+ icon = InfoIcon;
+ break;
+ case "requires_payment_method":
+ statusText = "Your payment was not successful, please try again.";
+ break;
+ default:
+ break;
+ }
+
+ document.querySelector("#status-icon").style.backgroundColor = iconColor;
+ document.querySelector("#status-icon").innerHTML = icon;
+ document.querySelector("#status-text").textContent= statusText;
+ document.querySelector("#intent-id").textContent = intent.id;
+ document.querySelector("#intent-status").textContent = intent.status;
+ document.querySelector("#view-details").href = `https://dashboard.stripe.com/payments/${intent.id}`;
+}
+
+function setErrorState() {
+ document.querySelector("#status-icon").style.backgroundColor = "#DF1B41";
+ document.querySelector("#status-icon").innerHTML = ErrorIcon;
+ document.querySelector("#status-text").textContent= "Something went wrong, please try again.";
+ document.querySelector("#details-table").classList.add("hidden");
+ document.querySelector("#view-details").classList.add("hidden");
+}
+
+// Stripe.js instance
+const stripe = Stripe("pk_test_51QfbSAAB1Vm8VfJq3AWsR4k2mZjnlF7XFrmlbc6XVXrtwXquAUfwzZmOFDbxMIAwqJBgqao8KLt2wmPc4vNOCTeo00WB78KtfV");
+
+checkStatus();
+
+// Fetches the payment intent status after payment submission
+async function checkStatus() {
+ const clientSecret = new URLSearchParams(window.location.search).get(
+ "payment_intent_client_secret"
+ );
+
+ if (!clientSecret) {
+ setErrorState();
+ return;
+ }
+
+ const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
+
+ setPaymentDetails(paymentIntent);
+}
+