Implement billing modal.

[?]
Feb 5, 2021, 6:48 AM
YBLHJFCNW52TJ37UIHPZ6UD22SQVGG27SP5UQR7YAIJ7F7SYJZSAC

Dependencies

  • [2] 3HTCTHHU Add halogen-portal dependency and update argonaut.
  • [3] N6FG4EW6 Working bootstrap modal! Only a little FFI.
  • [4] VTZT2ILU Wire up billing navigation.
  • [5] SAESJLLY Initial experiments in hash routing.
  • [6] ANDJ6GEY Add billing component skeleton.
  • [7] U7YAT2ZK Add error reporting to signup form.
  • [8] QH4UB73N Format with purty.
  • [9] PT4276XC Add logout functionality.
  • [10] T2DN23M7 Factor out billing create component.
  • [11] GLQSD33Y Use mock capability for overview init.
  • [12] 27H4DECZ Add billing create API call.
  • [13] 4GOBY5NQ WIP on modals.
  • [14] AAALU5A2 Fix client routing
  • [*] NJNMO72S Add zcash.com submodule and update client to modern halogen.
  • [*] RB2ETNIF Add skeletal PureScript client project.

Change contents

  • edit in client/spago.dhall at line 15
    [4.202]
    [4.202]
    , "numbers"
  • replacement in client/src/Aftok/Api/Billing.purs at line 9
    [4.153][2.604:684]()
    import Data.Argonaut.Decode (class DecodeJson, decodeJson, JsonDecodeError(..))
    [4.153]
    [4.212]
    import Data.Argonaut.Decode (class DecodeJson, decodeJson, JsonDecodeError(..), (.:))
  • edit in client/src/Aftok/Api/Billing.purs at line 14
    [4.421][4.251:292]()
    import Data.Interval.Duration (Duration)
  • replacement in client/src/Aftok/Api/Billing.purs at line 21
    [4.704][4.288:336]()
    import Data.Time.Duration (Hours(..), Days(..))
    [4.704]
    [4.315]
    import Data.Time.Duration (Hours)
  • replacement in client/src/Aftok/Api/Billing.purs at line 57
    [4.1524][4.1524:1555]()
    uuidStr <- decodeJson json
    [4.1524]
    [2.685]
    obj <- decodeJson json
    uuidStr <- obj .: "billableId"
  • replacement in client/src/Aftok/Api/Billing.purs at line 86
    [4.849][4.849:866]()
    { name: b.name
    [4.849]
    [4.866]
    { schemaVersion: "1.0"
    , name: b.name
  • edit in client/src/Aftok/Api/Billing.purs at line 93
    [4.1023]
    [4.1023]
    , gracePeriod: unwrap b.gracePeriod
    , requestExpiryPeriod: unwrap b.expiryPeriod
  • replacement in client/src/Aftok/Billing/Create.purs at line 6
    [4.607][4.607:696]()
    import Data.Either (Either(..))
    import Data.Foldable (all)
    import Data.Maybe (Maybe(..))
    [4.607]
    [4.696]
    import Data.Either (Either(..), note)
    import Data.Fixed as Fixed
    import Data.Foldable (any)
    import Data.Int as Int
    import Data.Maybe (Maybe(..), maybe)
    import Data.Newtype (unwrap)
    import Data.Number (fromString) as Number
    import Data.Number.Format (toString) as Number
  • edit in client/src/Aftok/Billing/Create.purs at line 15
    [4.727]
    [4.727]
    import Data.Validation.Semigroup (V(..), toEither)
  • replacement in client/src/Aftok/Billing/Create.purs at line 17
    [4.765][4.765:826]()
    import Data.Traversable (traverse)
    import Data.Tuple (Tuple)
    [4.765]
    [4.826]
    -- import Data.Traversable (traverse)
    import Data.Tuple (Tuple(..))
  • edit in client/src/Aftok/Billing/Create.purs at line 27
    [4.1076][4.1076:1116]()
    import Aftok.ProjectList as ProjectList
  • replacement in client/src/Aftok/Billing/Create.purs at line 28
    [4.1155][4.1155:1228]()
    import Aftok.Api.Types (APIError(..))
    import Aftok.Api.Project (Project)
    [4.1155]
    [3.464]
    import Aftok.HTML.Classes as C
  • edit in client/src/Aftok/Billing/Create.purs at line 31
    [3.535]
    [4.1228]
    import Aftok.Api.Types (APIError(..))
  • replacement in client/src/Aftok/Billing/Create.purs at line 35
    [4.1281][4.1281:1321]()
    , PaymentRequestId
    , PaymentRequest
    [4.1281]
    [4.1321]
    , Recurrence(..)
  • edit in client/src/Aftok/Billing/Create.purs at line 37
    [4.1340][4.1340:1395]()
    , listProjectBillables
    , listUnpaidPaymentRequests
  • edit in client/src/Aftok/Billing/Create.purs at line 38
    [4.1399]
    [4.1399]
    import Aftok.Zcash (ZEC(..), toZatoshi)
    data Field
    = NameField
    | DescField
    | MessageField
    | MonthlyRecurrenceField
    | WeeklyRecurrenceField
    | AmountField
    | GracePeriodField
    | RequestExpiryField
  • edit in client/src/Aftok/Billing/Create.purs at line 50
    [4.1400]
    [4.1400]
    derive instance fieldEq :: Eq Field
    derive instance fieldOrd :: Ord Field
  • edit in client/src/Aftok/Billing/Create.purs at line 59
    [4.1466]
    [4.1466]
    derive instance rtypeEq :: Eq RType
  • replacement in client/src/Aftok/Billing/Create.purs at line 66
    [4.1592][4.1592:1626]()
    , recurrenceType :: Maybe RType
    [4.1592]
    [4.1626]
    , recurrenceType :: RType
  • replacement in client/src/Aftok/Billing/Create.purs at line 68
    [4.1659][4.1659:1686]()
    , amount :: Maybe Number
    [4.1659]
    [4.1686]
    , amount :: Maybe ZEC
  • edit in client/src/Aftok/Billing/Create.purs at line 71
    [4.1750]
    [4.1750]
    , fieldErrors :: Array Field
  • replacement in client/src/Aftok/Billing/Create.purs at line 87
    [4.1974][4.1974:2035]()
    | SetRecurrenceDuration Number
    | SetBillingAmount Number
    [4.1974]
    [3.536]
    | SetRecurrenceMonths String
    | SetRecurrenceWeeks String
    | SetBillingAmount String
    | SetGracePeriod String
    | SetRequestExpiry String
  • replacement in client/src/Aftok/Billing/Create.purs at line 125
    [4.2709][4.2709:2740]()
    , recurrenceType : Nothing
    [4.2709]
    [4.2740]
    , recurrenceType : RTOneTime
  • edit in client/src/Aftok/Billing/Create.purs at line 130
    [4.2853]
    [4.2853]
    , fieldErrors : []
  • replacement in client/src/Aftok/Billing/Create.purs at line 135
    [4.2941][3.554:619]()
    Modals.modal "createBillable" "Create Billable" SaveBillable
    [4.2941]
    [3.619]
    Modals.modalWithSave "createBillable" "Create Billable" SaveBillable
  • replacement in client/src/Aftok/Billing/Create.purs at line 137
    [3.636][3.636:708]()
    [ HH.div
    [ P.classes (ClassName <$> ["form-group"]) ]
    [3.636]
    [3.708]
    [ formGroup st
    [ NameField ]
  • replacement in client/src/Aftok/Billing/Create.purs at line 140
    [3.730][3.730:861]()
    [ P.for "billableName", P.classes (ClassName <$> ["font-weight-bold", "mb-1"] )]
    [ HH.text "Bill Name:" ]
    [3.730]
    [3.861]
    [ P.for "billableName"]
    [ HH.text "Product Name" ]
  • replacement in client/src/Aftok/Billing/Create.purs at line 144
    [4.2101][4.2101:2163]()
    , P.classes (ClassName <$> [ "form-control-sm" ])
    [4.2101]
    [3.883]
    , P.classes [ C.formControlSm ]
  • edit in client/src/Aftok/Billing/Create.purs at line 147
    [3.1003][4.2265:2326](),[4.2265][4.2265:2326]()
    , P.required true
    , P.autofocus true
  • replacement in client/src/Aftok/Billing/Create.purs at line 149
    [4.2388][3.1053:1217]()
    , HH.label
    [ P.for "billableDesc", P.classes (ClassName <$> ["font-weight-bold", "mb-1"] )]
    [ HH.text "Bill Description:" ]
    [4.2388]
    [3.1217]
    ]
    , formGroup st
    [ DescField ]
    [ HH.label
    [ P.for "billableDesc"]
    [ HH.text "Product Description" ]
  • replacement in client/src/Aftok/Billing/Create.purs at line 157
    [3.1274][3.1274:1338]()
    , P.classes (ClassName <$> [ "form-control-sm" ])
    [3.1274]
    [3.1338]
    , P.classes [ C.formControlSm ]
  • edit in client/src/Aftok/Billing/Create.purs at line 160
    [3.1445][3.1445:1510]()
    , P.required true
    , P.autofocus true
  • replacement in client/src/Aftok/Billing/Create.purs at line 162
    [3.1576][3.1576:1755]()
    , HH.label
    [ P.for "billableMsg", P.classes (ClassName <$> ["font-weight-bold", "mb-1"] )]
    [ HH.text "Message to be included with bill:" ]
    [3.1576]
    [3.1755]
    ]
    , formGroup st
    [ MessageField ]
    [ HH.label
    [ P.for "billableMsg"]
    [ HH.text "Message to be included with bill" ]
  • edit in client/src/Aftok/Billing/Create.purs at line 170
    [3.1812][3.1812:1876]()
    , P.classes (ClassName <$> [ "form-control-sm" ])
  • replacement in client/src/Aftok/Billing/Create.purs at line 171
    [3.1912][3.1912:2097]()
    , P.placeholder "Description of the product or service"
    , P.required true
    , P.autofocus true
    , E.onValueInput (Just <<< SetDesc)
    [3.1912]
    [3.2097]
    , P.placeholder "Enter your message here"
    , E.onValueInput (Just <<< SetMessage)
    ]
    ]
    , formGroup st
    [MonthlyRecurrenceField, WeeklyRecurrenceField]
    [ HH.label_
    [ HH.input
    ([ P.type_ P.InputRadio
    , P.name "recurType"
    , E.onClick \_ -> Just (SetRecurrenceType RTAnnual)
    ] <> (if st.recurrenceType == RTAnnual then [P.checked true] else []))
    , HH.text " Annual"
    ]
    , HH.label_
    [ HH.input
    ([ P.type_ P.InputRadio
    , P.name "recurType"
    , E.onClick \_ -> Just (SetRecurrenceType RTMonthly)
    ] <> (if st.recurrenceType == RTMonthly then [P.checked true] else []))
    , HH.text " every "
    , HH.input
    [ P.type_ P.InputNumber
    , P.classes [ C.formControlSm ]
    , P.value (if st.recurrenceType == RTMonthly
    then maybe "" show st.recurrenceValue
    else "")
    , P.min 1.0
    , P.max 12.0
    , E.onValueInput (Just <<< SetRecurrenceMonths)
    ]
    , HH.text " Months"
    ]
    , HH.label_
    [ HH.input
    ([ P.type_ P.InputRadio
    , P.name "recurType"
    , E.onClick \_ -> Just (SetRecurrenceType RTWeekly)
    ] <> (if st.recurrenceType == RTWeekly then [P.checked true] else []))
    , HH.text " every "
    , HH.input
    [ P.type_ P.InputNumber
    , P.classes [ C.formControlSm ]
    , P.value (if st.recurrenceType == RTWeekly
    then maybe "" show st.recurrenceValue
    else "")
    , P.min 1.0
    , P.max 12.0
    , E.onValueInput (Just <<< SetRecurrenceWeeks)
    ]
    , HH.text " Weeks"
    ]
    , HH.label_
    [ HH.input
    ([ P.type_ P.InputRadio
    , P.name "recurType"
    , E.onClick \_ -> Just (SetRecurrenceType RTOneTime)
    ] <> (if st.recurrenceType == RTOneTime then [P.checked true] else []))
    , HH.text " One-Time"
    ]
    ]
    , formGroup st
    [AmountField]
    [ HH.label
    [ P.for "billableAmount"]
    [ HH.text "Amount" ]
    , HH.input
    [ P.type_ P.InputNumber
    , P.classes [ C.formControlSm ]
    , P.id_ "billableAmount"
    , P.value (maybe "" (Fixed.toString <<< unwrap) st.amount)
    , P.placeholder "1.0"
    , P.min 0.0
    , E.onValueInput (Just <<< SetBillingAmount)
  • edit in client/src/Aftok/Billing/Create.purs at line 246
    [3.2113]
    [3.2113]
    , HH.div
    [ P.classes [ ClassName "input-group-append" ] ]
    [ HH.span [ P.classes [ ClassName "input-group-text" ] ] [ HH.text "ZEC" ] ]
  • edit in client/src/Aftok/Billing/Create.purs at line 250
    [3.2125]
    [4.4003]
    , formGroup st
    [GracePeriodField]
    [ HH.label
    [ P.for "gracePeriod"]
    [ HH.text "Grace Period (Hours)" ]
    , HH.input
    [ P.type_ P.InputNumber
    , P.id_ "gracePeriod"
    , P.classes [ C.formControlSm ]
    , P.value (maybe "" (Number.toString <<< unwrap) st.gracePeriod)
    , P.placeholder "Hours until a bill is considered overdue"
    , P.min 0.0
    , E.onValueInput (Just <<< SetGracePeriod)
    ]
    ]
    , formGroup st
    [RequestExpiryField]
    [ HH.label
    [ P.for "requestExpiry"]
    [ HH.text "Request Expiry Period (Hours)" ]
    , HH.input
    [ P.type_ P.InputNumber
    , P.id_ "gracePeriod"
    , P.classes [ C.formControlSm ]
    , P.value (maybe "" (Number.toString <<< unwrap) st.requestExpiry)
    , P.placeholder "Hours until a payment request expires"
    , P.min 0.0
    , E.onValueInput (Just <<< SetRequestExpiry)
    ]
    ]
  • replacement in client/src/Aftok/Billing/Create.purs at line 283
    [4.2390][4.2390:2554]()
    colmd :: forall a s. Int -> Array (H.ComponentHTML a s m) -> H.ComponentHTML a s m
    colmd i xs = HH.div [ P.classes (ClassName <$> [ "col-md-" <> show i ]) ] xs
    [4.2390]
    [4.4021]
    formGroup :: forall i a. CState -> Array Field -> Array (HH.HTML i a) -> HH.HTML i a
    formGroup st fields body =
    HH.div
    [ P.classes [C.formGroup] ]
    (body <> (fieldError st =<< fields))
  • edit in client/src/Aftok/Billing/Create.purs at line 289
    [4.4022]
    [4.2555]
    fieldError :: forall i a. CState -> Field -> Array (HH.HTML i a)
    fieldError st field =
    if any (_ == field) st.fieldErrors
    then case field of
    NameField -> err "The name field is required"
    DescField -> err "The description field is required"
    MessageField -> err "The message field is required"
    MonthlyRecurrenceField -> err "You must enter a valid number of months."
    WeeklyRecurrenceField -> err "You must enter a valid number of weeks."
    AmountField -> err "You must enter a valid amount of ZEC"
    GracePeriodField -> err "You must enter a valid number of hours."
    RequestExpiryField -> err "You must enter a valid number of hours."
    else []
    where
    err str = [ HH.div_ [ HH.span [ P.classes (ClassName <$> [ "badge", "badge-danger-soft" ]) ] [ HH.text str ] ] ]
  • replacement in client/src/Aftok/Billing/Create.purs at line 309
    [4.4190][4.4190:4416](),[4.4416][3.2126:2219]()
    SetName name -> pure unit
    SetDesc desc -> pure unit
    SetMessage msg -> pure unit
    SetRecurrenceType rtype -> pure unit
    SetRecurrenceDuration dur -> pure unit
    SetBillingAmount amt -> pure unit
    SaveBillable ->
    lift $ system.toggleModal "createBillable" ModalFFI.HideModal
    [4.4190]
    [4.4416]
    SetName name ->
    H.modify_ (_ { name = Just name })
    SetDesc desc ->
    H.modify_ (_ { description = Just desc })
    SetMessage msg ->
    H.modify_ (_ { message = Just msg })
    SetRecurrenceType rtype -> do
    curRecurType <- H.gets _.recurrenceType
    curDuration <- H.gets _.recurrenceValue
    let rdur = case curRecurType of
    RTMonthly | rtype == RTMonthly -> curDuration
    RTWeekly | rtype == RTWeekly -> curDuration
    _ -> Nothing
    H.modify_ (_ { recurrenceType = rtype, recurrenceValue = rdur })
    SetRecurrenceMonths dur ->
    case Int.fromString dur of
    (Just n) -> H.modify_ (_ { recurrenceType = RTMonthly, recurrenceValue = Just n })
    (Nothing) -> pure unit
    SetRecurrenceWeeks dur ->
    case Int.fromString dur of
    (Just n) -> H.modify_ (_ { recurrenceType = RTWeekly, recurrenceValue = Just n })
    (Nothing) -> pure unit
    SetBillingAmount amt ->
    case Fixed.fromString amt of
    (Just zec) -> H.modify_ (_ { amount = Just (ZEC zec) })
    (Nothing) -> pure unit
    SetGracePeriod dur ->
    case Number.fromString dur of
    (Just n) -> H.modify_ (_ { gracePeriod = Just (Hours n) })
    (Nothing) -> pure unit
    SetRequestExpiry dur ->
    case Number.fromString dur of
    (Just n) -> H.modify_ (_ { requestExpiry = Just (Hours n) })
    (Nothing) -> pure unit
    SaveBillable -> do
    nameV <- V <<< note [NameField] <$> H.gets (_.name)
    descV <- V <<< note [DescField] <$> H.gets (_.description)
    msgV <- V <<< note [MessageField] <$> H.gets (_.message)
    rtype <- H.gets (_.recurrenceType)
    rvalueV <- case rtype of
    RTAnnual -> pure $ V (Right Annually)
    RTMonthly -> V <<< maybe (Left [MonthlyRecurrenceField]) (Right <<< Monthly) <$> H.gets (_.recurrenceValue)
    RTWeekly -> V <<< maybe (Left [WeeklyRecurrenceField]) (Right <<< Weekly) <$> H.gets (_.recurrenceValue)
    RTOneTime -> pure $ V (Right OneTime)
    zatsV <- V <<< maybe (Left [AmountField]) (Right <<< toZatoshi) <$> H.gets (_.amount)
    gperV <- V <<< note [GracePeriodField] <$> H.gets (_.gracePeriod)
    expiryV <- V <<< note [RequestExpiryField] <$> H.gets (_.requestExpiry)
    let toBillable = { name: _
    , description: _
    , message: _
    , recurrence: _
    , amount: _
    , gracePeriod: _
    , expiryPeriod: _
    }
    reqV :: V (Array Field) Billable
    reqV =
    toBillable <$> nameV
    <*> descV
    <*> msgV
    <*> rvalueV
    <*> zatsV
    <*> gperV
    <*> expiryV
    case toEither reqV of
    Left errors -> do
    H.modify_ (_ { fieldErrors = errors })
    Right billable -> do
    lift $ system.log "BILLABLE OK"
    pid <- H.gets (_.projectId)
    res <- lift $ caps.createBillable pid billable
    case res of
    Right bid -> do
    H.raise (Tuple bid billable)
    lift $ system.toggleModal "createBillable" ModalFFI.HideModal
    Left errs ->
    lift $ system.error (show errs)
    apiCapability :: Capability Aff
    apiCapability =
    { createBillable: createBillable
    }
  • edit in client/src/Aftok/Billing/Create.purs at line 394
    [4.4417]
    [3.2220]
    mockCapability :: Capability Aff
    mockCapability =
    { createBillable: \_ _ -> pure $ Left Forbidden }
  • file addition: PaymentRequest.purs (----------)
    [4.454]
    module Aftok.Billing.PaymentRequest where
    {--
    <div role="document" class="ant-modal" style="width: 520px; transform-origin: 724px 147.062px;">
    <div tabindex="0" style="width: 0px; height: 0px; overflow: hidden;">sentinelStart</div>
    <div class="ant-modal-content"><button aria-label="Close" class="ant-modal-close"><span class="ant-modal-close-x"><i aria-label="icon: close" class="anticon anticon-close ant-modal-close-icon"><svg viewBox="64 64 896 896" class="" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></i></span></button>
    <div class="ant-modal-header">
    <div class="ant-modal-title" id="rcDialogTitle0">Tip a proposal</div>
    </div>
    <div class="ant-modal-body">
    <div class="TipJarModal">
    <div class="TipJarModal-uri">
    <div>
    <div class="TipJarModal-uri-qr"><span style="opacity: 1;"><canvas height="128" width="128" style="height: 128px; width: 128px;"></canvas></span></div>
    </div>
    <div class="TipJarModal-uri-info">
    <div class="ant-row ant-form-item TipJarModal-uri-info-input CopyInput">
    <div class="ant-form-item-label"><label class="" title="Amount">Amount</label></div>
    <div class="ant-form-item-control-wrapper">
    <div class="ant-form-item-control"><span class="ant-form-item-children"><span class="ant-input-group-wrapper"><span class="ant-input-wrapper ant-input-group"><input type="number" placeholder="Amount to send" class="ant-input" value="0.2"><span class="ant-input-group-addon">ZEC</span></span>
    </span>
    </span>
    </div>
    </div>
    </div>
    <div class="ant-row ant-form-item CopyInput TipJarModal-uri-info-input is-textarea">
    <div class="ant-form-item-label"><label class="" title="Payment URI">Payment URI</label></div>
    <div class="ant-form-item-control-wrapper">
    <div class="ant-form-item-control"><span class="ant-form-item-children"><textarea readonly="" rows="3" class="ant-input">zcash:zs1xzymv205x8hhn8kt3pu43c6knjlelvxfgzgsyyus9yxhmdvqeu0yj0m2knzd3p93slsygkp94rz?amount=0.2</textarea><button type="button" class="ant-btn ant-btn-icon-only"><i aria-label="icon: copy" class="anticon anticon-copy"><svg viewBox="64 64 896 896" class="" data-icon="copy" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"></path></svg></i></button></span></div>
    </div>
    </div><a href="zcash:zs1xzymv205x8hhn8kt3pu43c6knjlelvxfgzgsyyus9yxhmdvqeu0yj0m2knzd3p93slsygkp94rz?amount=0.2" class="ant-btn ant-btn-ghost ant-btn-lg ant-btn-block"><span>Open in Wallet </span><i aria-label="icon: link" class="anticon anticon-link"><svg viewBox="64 64 896 896" class="" data-icon="link" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M574 665.4a8.03 8.03 0 0 0-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 0 0-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 0 0 0 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 0 0 0 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 0 0-11.3 0L372.3 598.7a8.03 8.03 0 0 0 0 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"></path></svg></i></a></div>
    </div>
    <div class="TipJarModal-fields">
    <div class="TipJarModal-fields-row">
    <div class="ant-row ant-form-item CopyInput TipJarModal-fields-row-address">
    <div class="ant-form-item-label"><label class="" title="Address">Address</label></div>
    <div class="ant-form-item-control-wrapper">
    <div class="ant-form-item-control"><span class="ant-form-item-children"><input readonly="" type="text" class="ant-input" value="zs1xzymv205x8hhn8kt3pu43c6knjlelvxfgzgsyyus9yxhmdvqeu0yj0m2knzd3p93slsygkp94rz"><button type="button" class="ant-btn ant-btn-icon-only"><i aria-label="icon: copy" class="anticon anticon-copy"><svg viewBox="64 64 896 896" class="" data-icon="copy" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"></path></svg></i></button></span></div>
    </div>
    </div>
    </div>
    <div class="TipJarModal-fields-row">
    <div class="ant-row ant-form-item ant-form-item-with-help CopyInput">
    <div class="ant-form-item-label"><label class="" title="Zcash CLI command">Zcash CLI command</label></div>
    <div class="ant-form-item-control-wrapper">
    <div class="ant-form-item-control"><span class="ant-form-item-children"><input readonly="" type="text" class="ant-input" value="zcash-cli z_sendmany YOUR_ADDRESS '[{&quot;address&quot;:&quot;zs1xzymv205x8hhn8kt3pu43c6knjlelvxfgzgsyyus9yxhmdvqeu0yj0m2knzd3p93slsygkp94rz&quot;,&quot;amount&quot;:0.2}]'"><button type="button" class="ant-btn ant-btn-icon-only"><i aria-label="icon: copy" class="anticon anticon-copy"><svg viewBox="64 64 896 896" class="" data-icon="copy" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"></path></svg></i></button></span>
    <div class="ant-form-explain">Make sure you replace YOUR_ADDRESS with your actual address</div>
    </div>
    </div>
    </div>
    </div>
    </div>
    </div>
    </div>
    <div class="ant-modal-footer"><button type="button" class="ant-btn ant-btn-primary"><span>Done</span></button></div>
    </div>
    <div tabindex="0" style="width: 0px; height: 0px; overflow: hidden;">sentinelEnd</div>
    </div>
    --}
  • edit in client/src/Aftok/Billing.purs at line 33
    [4.3596][4.3596:3615]()
    , createBillable
  • edit in client/src/Aftok/Billing.purs at line 69
    [4.4535][4.4535:4536]()
  • replacement in client/src/Aftok/Billing.purs at line 157
    [4.7142][4.5211:5266]()
    { createBillable: { createBillable: createBillable }
    [4.7142]
    [4.7177]
    { createBillable: Create.apiCapability
  • edit in client/src/Aftok/HTML/Classes.purs at line 43
    [4.3987]
    formGroup :: ClassName
    formGroup = ClassName "form-group"
    formControlSm :: ClassName
    formControlSm = ClassName "form-control-sm"
  • replacement in client/src/Aftok/Modals.purs at line 25
    [4.5065][3.3270:3280]()
    modal ::
    [4.5065]
    [3.3280]
    modalWithSave ::
  • replacement in client/src/Aftok/Modals.purs at line 32
    [3.3422][3.3422:3460]()
    modal modalId title submit contents =
    [3.3422]
    [4.5172]
    modalWithSave modalId title submit contents =
  • replacement in client/src/Aftok/Modals.purs at line 54
    [4.5804][4.5804:5868]()
    [ HH.span [ARIA.hidden "true"] [HH.text "&times;"]]
    [4.5804]
    [4.5868]
    [ HH.span [ARIA.hidden "true"] [HH.text "×"]]
  • replacement in client/src/Aftok/Zcash.purs at line 6
    [4.1637][4.1637:1684]()
    import Data.Fixed (Fixed, P1000000, TenTimes)
    [4.1637]
    [4.1684]
    import Data.BigInt (toString) as BigInt
    import Data.Fixed (Fixed, P1000000, TenTimes, fromInt, numerator)
    import Data.Fixed (toString) as Fixed
  • edit in client/src/Aftok/Zcash.purs at line 17
    [4.1875]
    [4.1875]
    zatsString :: Zatoshi -> String
    zatsString (Zatoshi z) = BigInt.toString z
  • edit in client/src/Aftok/Zcash.purs at line 30
    [4.2064]
    [4.2064]
    zecString :: ZEC -> String
    zecString (ZEC z) = Fixed.toString z
  • edit in client/src/Aftok/Zcash.purs at line 34
    [4.2065]
    toZatoshi :: ZEC -> Zatoshi
    toZatoshi (ZEC z) =
    Zatoshi (numerator z)
  • edit in client/src/Main.purs at line 46
    [4.19689]
    [4.1684]
    billing = Billing.apiCapability
  • edit in client/src/Main.purs at line 49
    [4.1685][4.756:795]()
    billing = Billing.mockCapability