{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
%} {% block page %}

<q-dialog v-model="thingDialog.show" position="top">
  <q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
    <q-form @submit="sendThingDialog" class="q-gutter-md">
      <q-input
        filled
        dense
        v-model.trim="thingDialog.data.name"
        type="text"
        label="Name *"
      ></q-input>
      <q-input
        filled
        dense
        v-model.trim="thingDialog.data.email"
        type="email"
        label="Name *"
      ></q-input>
      <q-select
        filled
        dense
        emit-value
        v-model="thingDialog.data.wallet"
        :options="g.user.walletOptions"
        label="Wallet *"
      ></q-select>
      <div class="row q-mt-lg">
        <q-btn
          v-if="thingDialog.data.id"
          unelevated
          color="primary"
          type="submit"
          >Update thing</q-btn
        >
        <q-btn
          v-else
          unelevated
          color="primary"
          :disable="thingDialog.data.name == null"
          type="submit"
          >Create thing</q-btn
        >
        <q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
      </div>
    </q-form>
  </q-card>
</q-dialog>

<q-card flat>
  <q-card-section>
    <div class="text-h5 q-mb-md">
      Extension Development Guide
      <small
        >(also check the
        <a
          class="text-primary"
          href="http://docs.lnbits.org/devs/development.html"
          >docs</a
        >)</small
      >
    </div>

    <q-card unelevated flat>
      <q-tabs
        v-model="tab"
        dense
        class="text-grey"
        active-color="primary"
        indicator-color="primary"
        align="justify"
        narrow-indicator
      >
        <q-tab name="frameworks" label="Frameworks"></q-tab>
        <q-tab name="tools" label="Useful Tools"></q-tab>
        <q-tab name="goodpractice" label="Good Practice"></q-tab>
        <q-tab name="enviroment" label="Dev Enviroment"></q-tab>
        <q-tab name="submission" label="Submisson to LNbits repo"></q-tab>
      </q-tabs>

      <q-separator></q-separator>

      <q-tab-panels v-model="tab">
        <q-tab-panel name="frameworks">
          <div class="text-h6">Frameworks</div>

          <div>
            <template>
              <q-tabs align="left" v-model="framworktab" inline-label>
                <q-tab name="fastapi"
                  ><img src="./static/fastapi-framework.png" />FASTAPI</q-tab
                >
                <q-tab name="quasar"
                  ><img src="./static/quasar-framework.png" />QUASAR</q-tab
                >
                <q-tab name="vuejs"
                  ><img src="./static/vuejs-framework.png" />VUE-JS</q-tab
                >
              </q-tabs>
            </template>

            <template>
              <q-tab-panels v-model="framworktab">
                <q-tab-panel name="fastapi" class="text-body1">
                  <a href="https://fastapi.tiangolo.com/"
                    ><img src="./static/fastapilogo.png"
                  /></a>
                  <p>
                    LNbits API is built using
                    <a href="https://fastapi.tiangolo.com/" class="text-primary"
                      >FastAPI</a
                    >, a high-performance, easy to code API framework.<br /><br />
                    FastAPI auto-generates swagger UI docs for testing endpoints
                    <a class="text-primary" href="../docs">/docs</a>
                  </p>

                  <i>
                    <strong>TIP:</strong> Although it is possible for extensions
                    to use other extensions API endpoints (such as with the
                    Satspay and Onchain extension), ideally an extension should
                    only use LNbits
                    <a href="../docs#/default" class="text-primary">core</a>
                    endpoints. </i
                  ><br /><br />

                  <code class="bg-grey-3 text-black">views.py</code> is used for
                  setting application routes:
                  <img src="./static/fastapi-example.png" /><br /><br />
                  <code class="bg-grey-3 text-black">views_api.py</code> is used
                  for setting application API endpoints:<br />
                  <img src="./static/fastapi-example2.png" />
                </q-tab-panel>

                <q-tab-panel name="quasar" class="text-body1">
                  <a href="https://quasar.dev/"
                    ><img src="./static/quasarlogo.png"
                  /></a>
                  <p>
                    LNbits uses
                    <a class="text-primary" href="https://quasar.dev/"
                      >Quasar Framework</a
                    >
                    for frontend deisgn elements. Quasar Framework is an
                    open-source Vue.js based framework for building apps.
                  </p>

                  <i>
                    <strong>TIP:</strong> Look through
                    <code class="bg-grey-3 text-black">/template</code> files in
                    other extensions for examples of Quasar elements being used. </i
                  ><br /><br />

                  <p>
                    In the below example we make a dialogue popup box (box can
                    be triggered
                    <q-btn
                      size="sm"
                      color="primary"
                      @click="thingDialog.show = true"
                      >here</q-btn
                    >): <q-tooltip>Exmple of a tooltip!</q-tooltip>
                  </p>
                  <img src="./static/quasar-example.png" /><br /><br />
                  <div class="text-h6">Useful links:</div>
                  <q-btn
                    color="primary"
                    type="a"
                    href="https://quasar.dev/style/"
                    >Style (typography, spacing, etc)</q-btn
                  >
                  <q-btn
                    color="primary"
                    type="a"
                    href="https://quasar.dev/vue-components/"
                    >Genral components (cards, buttons, popup dialogs,
                    etc)</q-btn
                  >
                  <q-btn
                    color="primary"
                    type="a"
                    href="https://quasar.dev/layout/grid"
                    >Layouts (rows/columns, flexbox)</q-btn
                  >
                </q-tab-panel>

                <q-tab-panel
                  v-if="someBool == true"
                  name="vuejs"
                  class="text-body1"
                >
                  <a href="https://vuejs.org/">
                    <img src="./static/vuejslogo.png"
                  /></a>
                  <p>
                    LNbits uses
                    <a href="https://vuejs.org/" class="text-primary">Vue</a>
                    for best-in-class, responsive and high-performance
                    components.
                  </p>

                  <p>Typical example of Vue components in a frontend script:</p>
                  <img
                    src="./static/script-example.png"
                    style="max-width: 800px"
                  /><br /><br />

                  <p>
                    Content can be conditionally rendered using Vue's
                    <code class="bg-grey-3 text-black">v-if</code>:
                  </p>
                  <img
                    src="./static/vif-example.png"
                    style="max-width: 800px"
                  />
                </q-tab-panel>
              </q-tab-panels>
            </template>
          </div>
        </q-tab-panel>

        <q-tab-panel name="tools">
          <div class="text-h6">Useful Tools</div>
          <div>
            <template>
              <q-tabs v-model="usefultab" align="left">
                <q-tab name="magicalg">MAGICAL G</q-tab>
                <q-tab name="exchange">EXCHANGE RATES</q-tab>
                <q-tab name="qrcodes">QR CODES</q-tab>
                <q-tab name="websockets">WEBSOCKETS</q-tab>
              </q-tabs>
            </template>

            <template>
              <q-tab-panels v-model="usefultab">
                <q-tab-panel name="magicalg" class="text-body1">
                  <div class="text-h5 q-mb-md">Magical G</div>
                  <p>
                    A magical "g" (ie
                    <code class="bg-grey-3 text-black"
                      >this.g.user.wallets[0].inkey</code
                    >) is always available, with info about the user, wallets
                    and extensions:
                  </p>
                  <code class="text-caption">{% raw %}{{ g }}{% endraw %}</code>
                </q-tab-panel>
                <q-tab-panel name="exchange">
                  <div class="text-h6">Exchange rates</div>
                  <p>
                    LNbits includes a handy
                    <a
                      href="../docs#/default/api_fiat_as_sats_api_v1_conversion_post"
                      class="text-primary"
                      >exchange rate function</a
                    >, that streams rates from 6 different sources.
                  </p>
                  Exchange rate API:<br />
                  <img src="./static/conversion-example.png" /><br /><br />
                  Exchange rate functions, included using
                  <code class="bg-grey-3 text-black"
                    >from lnbits.utils.exchange_rates import
                    fiat_amount_as_satoshis</code
                  >:<br />
                  <img src="./static/conversion-example2.png" />
                </q-tab-panel>
                <q-tab-panel name="qrcodes" class="text-body1">
                  <div class="text-h5 q-mb-md">QR Codes</div>
                  <p>
                    For most purposes use Quasar's inbuilt VueQrcode library:
                  </p>
                  <img src="./static/qrcode-example1.png" />
                  <p>
                    LNbits does also include a handy
                    <a
                      href="../docs#/default/img_api_v1_qrcode__data__get"
                      class="text-primary"
                    >
                      QR code enpoint</a
                    >
                  </p>
                  {% raw %} You can use via
                  <a
                    href="/api/v1/qrcode/some-data-you-want-in-a-qrcode"
                    class="text-primary"
                    >{{protocol + location}}{% endraw
                    %}/api/v1/qrcode/some-data-you-want-in-a-qrcode:</a
                  ><br />
                  <br />
                  <img src="./static/qrcode-example.png" />
                  <br />
                  <img
                    class="bg-white"
                    width="300px"
                    src="/api/v1/qrcode/some-data-you-want-in-a-qrcode"
                  />

                  <br />
                </q-tab-panel>

                <q-tab-panel name="websockets" class="text-body1">
                  <div class="text-h5 q-mb-md">Websockets</div>
                  <p>
                    Fastapi includes a great
                    <a
                      class="text-primary"
                      href="https://fastapi.tiangolo.com/advanced/websockets/#websockets-client"
                      >websocket tool</a
                    >
                  </p>
                  {% raw %}
                  <p>
                    A few LNbits extensions also make use of a weird and useful
                    websocket/GET tool built into LNbits, such as extensions
                    Copilot and LNURLDevices<br />
                    You can subscribe to websocket with
                    <code class="bg-grey-3 text-black"
                      >wss:{{location}}/api/v1/ws/{SOME-ID}</code
                    ><br />
                    You can post to any clients subscribed to the endpoint with
                    <code class="bg-grey-3 text-black"
                      >{{protocol +
                      location}}/api/v1/ws/{SOME-ID}/{THE-DATA-YOU-WANT-TO-POST}</code
                    ><br />
                    <br />
                    <strong
                      ><div id="text-to-change">
                        DEMO: Hit
                        <a
                          target="_blank"
                          href="/api/v1/ws/32872r23g29/blah%20blah%20blah"
                          class="text-primary"
                          >{{protocol +
                          location}}/api/v1/ws/32872r23g29/blah%20blah%20blah</a
                        >
                        in a different browser window to change this text to
                        `blah blah blah`.
                      </div></strong
                    >
                    <br />
                    Function used in this demo:<br />
                    <img src="./static/websocket-example.png" /></p
                ></q-tab-panel>

                {% endraw %}
              </q-tab-panels>
            </template>
          </div>
        </q-tab-panel>

        <q-tab-panel name="goodpractice">
          <div class="text-h6">Good Practice</div>
          Coming soon...
        </q-tab-panel>

        <q-tab-panel name="enviroment">
          <div class="text-h6">Dev Enviroment</div>
          Coming soon...
        </q-tab-panel>

        <q-tab-panel name="submission">
          <div class="text-h6">Submission</div>
          Coming soon...
        </q-tab-panel>
      </q-tab-panels>
    </q-card>
  </q-card-section>
</q-card>
{% endblock %} {% block scripts %} {{ window_vars(user) }}

<script>
  var someMapObject = obj => {
    obj._data = _.clone(obj)
    obj.date = Quasar.utils.date.formatDate(
      new Date(obj.time * 1000),
      'YYYY-MM-DD HH:mm'
    )
    // here you can do something with the mapped data
    return obj
  }
  new Vue({
    el: '#vue',
    mixins: [windowMixin],
    data: function () {
      return {
        ///// Declare models/variables /////
        protocol: window.location.protocol,
        location: '//' + window.location.hostname,
        thingDialog: {
          show: false,
          data: {}
        },
        someBool: true,
        splitterModel: 20,
        exampleData: [],
        tab: 'frameworks',
        framworktab: 'fastapi',
        usefultab: 'magicalg'
      }
    },
    ///// Where functions live /////
    methods: {
      exampleFunction: function (data) {
        var theData = data
        LNbits.api
          .request(
            'GET', // Type of request
            '/example/api/v1/test/' + theData, // URL of the endpoint
            this.g.user.wallets[0].inkey // Often endpoints require a key
          )
          .then(response => {
            this.exampleData = response.data.map(someMapObject) // Often whats returned is mapped onto some model
          })
          .catch(error => {
            LNbits.utils.notifyApiError(error) // Error will be passed to the frontend
          })
      },
      initWs: async function () {
        if (location.protocol !== 'http:') {
          localUrl =
            'wss://' +
            document.domain +
            ':' +
            location.port +
            '/api/v1/ws/32872r23g29'
        } else {
          localUrl =
            'ws://' +
            document.domain +
            ':' +
            location.port +
            '/api/v1/ws/32872r23g29'
        }
        this.ws = new WebSocket(localUrl)
        this.ws.addEventListener('message', async ({data}) => {
          const res = data.toString()
          document.getElementById('text-to-change').innerHTML = res
        })
      },
      sendThingDialog() {
        console.log(this.thingDialog)
      }
    },
    ///// To run on startup /////
    created: function () {
      self = this // Often used to run a real object, rather than the event (all a bit confusing really)
      self.exampleFunction('lorum')
      self.initWs()
    }
  })
</script>
{% endblock %}
