-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First instance of being able to collect card info and make a payment
- Loading branch information
1 parent
38e4e38
commit cdfff5b
Showing
40 changed files
with
751 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
name: Release | ||
on: | ||
push: | ||
branches: [master, main] | ||
branches: [master, main, dev] | ||
tags: ["*"] | ||
jobs: | ||
publish: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
115 changes: 115 additions & 0 deletions
115
harness-payments/js/src/main/scala/harness/payments/PaymentsUI.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package harness.payments | ||
|
||
import harness.core.* | ||
import harness.http.client.HttpClient | ||
import harness.payments.facades.* | ||
import harness.webUI.* | ||
import harness.webUI.style.{given, *} | ||
import harness.webUI.vdom.{given, *} | ||
import harness.webUI.widgets.* | ||
import harness.zio.* | ||
import org.scalajs.dom.{console, document, window} | ||
import scala.util.matching.Regex | ||
import zio.* | ||
|
||
object PaymentsUI { | ||
|
||
private val loader: Promise[Nothing, Unit] = | ||
Unsafe.unsafely { Runtime.default.unsafe.run { Promise.make[Nothing, Unit] }.getOrThrow() } | ||
|
||
val addStripeSrc: HRIO[Logger, Unit] = | ||
Logger.log.debug("Loading stripe src") *> | ||
ZIO | ||
.hAttempt { | ||
val elem = document.createElement("script") | ||
elem.setAttribute("src", "https://js.stripe.com/v3/") | ||
elem.asInstanceOf[scalajs.js.Dynamic].onload = { (_: Any) => | ||
Unsafe.unsafely { Runtime.default.unsafe.run { loader.done(Exit.Success(())) }.getOrThrow() } | ||
} | ||
document.head.append(elem) | ||
} | ||
.mapError(HError.SystemFailure("Unable to add stripe src", _)) | ||
|
||
val awaitStripeSrc: UIO[Unit] = | ||
loader.await | ||
|
||
private val elementName: String = "payment-element" | ||
|
||
def createAndMountElements(payments: PaymentEnv, currency: Currency): HTask[Unit] = | ||
ZIO | ||
.hAttempt { | ||
val options = ElementsOptions("setup", currency.toString.toLowerCase) | ||
val elements = payments.stripe.elements(options) | ||
val paymentElement = elements.create("payment") | ||
paymentElement.mount(s"#$elementName") | ||
elements | ||
} | ||
.mapError(HError.SystemFailure("Unable to create & mount stripe payments elements", _)) | ||
.flatMap(payments.elementsRef.set) | ||
|
||
private implicit class MaybeErrorOps(maybeError: MaybeErrorResponse) { | ||
def toZIO: HTask[Unit] = | ||
maybeError.error.toOption match { | ||
case Some(error) => ZIO.fail(HError.UserError(s"[TODO - message]: ${error.message}")) | ||
case None => ZIO.unit | ||
} | ||
} | ||
|
||
final class PaymentEnv private ( | ||
private[PaymentsUI] val stripe: Stripe, | ||
private[PaymentsUI] val elementsRef: Ref[Elements], | ||
) { | ||
|
||
val elements: UIO[Elements] = | ||
elementsRef.get.tap { elements => ZIO.dieMessage("elements not populated").when(elements == null) } | ||
|
||
} | ||
object PaymentEnv { | ||
|
||
def create(apiKey: String): UIO[PaymentEnv] = | ||
Ref.make[Elements](null).map { new PaymentEnv(Stripe(apiKey), _) } | ||
|
||
} | ||
|
||
private val getUrlRegex: Regex = | ||
s"^(https?://[^/]+)".r | ||
|
||
def paymentForm( | ||
createIntent: HRIO[HttpClient.ClientT & Logger & Telemetry, ClientSecret], | ||
paymentsEnv: PaymentEnv, | ||
redirectUrl: Url, | ||
): CModifier = | ||
PModifier.builder | ||
.withAction[Submit] { rh => | ||
form( | ||
id := "payment-form", | ||
div( | ||
id := elementName, | ||
), | ||
FormWidgets | ||
.submitButton( | ||
"Submit", | ||
) | ||
.flatMapActionZM(_ => ZIO.succeed(Nil)), // otherwise we submit twice, consider making normal button? | ||
onSubmit := { event => | ||
event.preventDefault() | ||
rh.raiseAction(Submit) | ||
}, | ||
) | ||
} | ||
.flatMapActionZM { _ => | ||
for { | ||
elements <- paymentsEnv.elements | ||
_ <- ZIO.fromPromiseJS { elements.submit() }.mapError(HError.fromThrowable).flatMap(_.toZIO) | ||
clientSecret <- createIntent | ||
_ <- Logger.log.info(s"clientSecret: $clientSecret") | ||
host = s"${window.location.protocol}//${window.location.host}" | ||
_ <- | ||
ZIO | ||
.fromPromiseJS { paymentsEnv.stripe.confirmSetup(new ConfirmSetupOptions(elements, clientSecret.value, new ConfirmParams(s"$host${redirectUrl.toString}"))) } | ||
.mapError(HError.fromThrowable) | ||
.flatMap(_.toZIO) | ||
} yield Nil | ||
} | ||
|
||
} |
7 changes: 7 additions & 0 deletions
7
harness-payments/js/src/main/scala/harness/payments/facades/ConfirmParams.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package harness.payments.facades | ||
|
||
import scala.scalajs.js | ||
|
||
final class ConfirmParams( | ||
val `return_url`: String, | ||
) extends js.Object |
9 changes: 9 additions & 0 deletions
9
harness-payments/js/src/main/scala/harness/payments/facades/ConfirmSetupOptions.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package harness.payments.facades | ||
|
||
import scala.scalajs.js | ||
|
||
final class ConfirmSetupOptions( | ||
val elements: Elements, | ||
val clientSecret: String, | ||
val confirmParams: ConfirmParams | ||
) extends js.Object |
9 changes: 9 additions & 0 deletions
9
harness-payments/js/src/main/scala/harness/payments/facades/Elements.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package harness.payments.facades | ||
|
||
import scalajs.js | ||
|
||
@js.native | ||
trait Elements extends js.Object { | ||
def create(str: String): PaymentElement | ||
def submit(): js.Promise[MaybeErrorResponse] | ||
} |
9 changes: 9 additions & 0 deletions
9
harness-payments/js/src/main/scala/harness/payments/facades/ElementsOptions.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package harness.payments.facades | ||
|
||
import scalajs.js | ||
|
||
final class ElementsOptions( | ||
val mode: String, | ||
val currency: String, | ||
// TODO (KR) : appearance | ||
) extends js.Object |
10 changes: 10 additions & 0 deletions
10
harness-payments/js/src/main/scala/harness/payments/facades/Err.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package harness.payments.facades | ||
|
||
import scala.scalajs.js | ||
|
||
@js.native | ||
trait Err extends js.Object { | ||
val code: String | ||
val message: String | ||
val `type`: String | ||
} |
8 changes: 8 additions & 0 deletions
8
harness-payments/js/src/main/scala/harness/payments/facades/MaybeErrorResponse.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package harness.payments.facades | ||
|
||
import scala.scalajs.js | ||
|
||
@js.native | ||
trait MaybeErrorResponse extends js.Object { | ||
def error: js.UndefOr[Err] | ||
} |
8 changes: 8 additions & 0 deletions
8
harness-payments/js/src/main/scala/harness/payments/facades/PaymentElement.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package harness.payments.facades | ||
|
||
import scala.scalajs.js | ||
|
||
@js.native | ||
trait PaymentElement extends js.Object { | ||
def mount(str: String): js.Any | ||
} |
11 changes: 11 additions & 0 deletions
11
harness-payments/js/src/main/scala/harness/payments/facades/Stripe.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package harness.payments.facades | ||
|
||
import scalajs.js | ||
import scalajs.js.annotation.* | ||
|
||
@js.native | ||
@JSGlobal | ||
final class Stripe(apiKey: String) extends js.Any { | ||
def elements(options: ElementsOptions): Elements = js.native | ||
def confirmSetup(confirmSetupOptions: ConfirmSetupOptions): js.Promise[MaybeErrorResponse] = js.native | ||
} |
8 changes: 8 additions & 0 deletions
8
harness-payments/jvm/src/main/scala/harness/payments/CardInfo.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package harness.payments | ||
|
||
final case class CardInfo( | ||
cardNumber: String, | ||
expMonth: Int, | ||
expYear: Int, | ||
cvc: String | ||
) |
11 changes: 11 additions & 0 deletions
11
harness-payments/jvm/src/main/scala/harness/payments/Charge.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package harness.payments | ||
|
||
import harness.email.* | ||
|
||
final case class Charge( | ||
amountInCents: Long, | ||
currency: Currency, | ||
description: String, | ||
source: PaymentSourceId, | ||
email: Option[EmailAddress], | ||
) |
8 changes: 8 additions & 0 deletions
8
harness-payments/jvm/src/main/scala/harness/payments/CreateCustomer.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package harness.payments | ||
|
||
import harness.email.* | ||
|
||
final case class CreateCustomer( | ||
name: Option[String], | ||
email: Option[EmailAddress], | ||
) |
12 changes: 12 additions & 0 deletions
12
harness-payments/jvm/src/main/scala/harness/payments/JvmIds.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package harness.payments | ||
|
||
import harness.pk.StringId | ||
|
||
type ChargeId = ChargeId.Id | ||
object ChargeId extends StringId | ||
|
||
type PaymentId = PaymentId.Id | ||
object PaymentId extends StringId | ||
|
||
type PaymentSourceId = PaymentSourceId.Id | ||
object PaymentSourceId extends StringId |
12 changes: 12 additions & 0 deletions
12
harness-payments/jvm/src/main/scala/harness/payments/Payment.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package harness.payments | ||
|
||
import harness.email.* | ||
|
||
final case class Payment( | ||
customerId: CustomerId, | ||
paymentMethodId: PaymentMethodId, | ||
amountInCents: Long, | ||
currency: Currency, | ||
description: String, | ||
email: Option[EmailAddress] | ||
) |
Oops, something went wrong.