From 18193778971e27d18b5a35df8c2d0e2953b48111 Mon Sep 17 00:00:00 2001
From: Ramires Viana <59319979+ramiresviana@users.noreply.github.com>
Date: Tue, 16 Feb 2021 15:39:11 +0000
Subject: [PATCH] feat: improved sharing prompt

---
 frontend/public/themes/dark.css           |   4 +-
 frontend/src/components/prompts/Share.vue | 172 +++++++++++++---------
 frontend/src/css/_share.css               |   7 +-
 frontend/src/css/dashboard.css            |  12 ++
 http/share.go                             |  12 --
 5 files changed, 116 insertions(+), 91 deletions(-)

diff --git a/frontend/public/themes/dark.css b/frontend/public/themes/dark.css
index 9a5be1f7..2a70351c 100644
--- a/frontend/public/themes/dark.css
+++ b/frontend/public/themes/dark.css
@@ -119,8 +119,8 @@ nav > div {
 .dashboard p label {
   color: var(--textPrimary);
 }
-.card#share ul li input,
-.card#share ul li select,
+.card#share input,
+.card#share select,
 .input {
   background: var(--surfaceSecondary);
   color: var(--textPrimary);
diff --git a/frontend/src/components/prompts/Share.vue b/frontend/src/components/prompts/Share.vue
index 043847d8..f4163975 100644
--- a/frontend/src/components/prompts/Share.vue
+++ b/frontend/src/components/prompts/Share.vue
@@ -4,61 +4,82 @@
       <h2>{{ $t('buttons.share') }}</h2>
     </div>
 
-    <div class="card-content">
-      <ul>
+    <template v-if="listing">
+      <div class="card-content">
+        <table>
+          <tr>
+            <th>#</th>
+            <th>{{ $t('settings.shareDuration') }}</th>
+            <th></th>
+            <th></th>
+          </tr>
 
-        <li v-for="link in links" :key="link.hash">
-          <a :href="buildLink(link.hash)" target="_blank">
-            <template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
-            <template v-else>{{ $t('permanent') }}</template>
-          </a>
+          <tr v-for="link in links" :key="link.hash">
+            <td>{{ link.hash }}</td>
+            <td>
+              <template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
+              <template v-else>{{ $t('permanent') }}</template>
+            </td>
+            <td class="small">
+              <button class="action copy-clipboard"
+                :data-clipboard-text="buildLink(link.hash)"
+                :aria-label="$t('buttons.copyToClipboard')"
+                :title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
+            </td>
+            <td class="small">
+              <button class="action"
+                @click="deleteLink($event, link)"
+                :aria-label="$t('buttons.delete')"
+                :title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
+            </td>
+          </tr>
+        </table>
+      </div>
 
-          <button class="action"
-            @click="deleteLink($event, link)"
-            :aria-label="$t('buttons.delete')"
-            :title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
+      <div class="card-action">
+        <button class="button button--flat button--grey"
+          @click="$store.commit('closeHovers')"
+          :aria-label="$t('buttons.close')"
+          :title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
+        <button class="button button--flat button--blue"
+          @click="() => switchListing()"
+          :aria-label="$t('buttons.new')"
+          :title="$t('buttons.new')">{{ $t('buttons.new') }}</button>
+      </div>
+    </template>
 
-          <button class="action copy-clipboard"
-            :data-clipboard-text="buildLink(link.hash)"
-            :aria-label="$t('buttons.copyToClipboard')"
-            :title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
-        </li>
+    <template v-else>
+      <div class="card-content">
+        <p>{{ $t('settings.shareDuration') }}</p>
+        <div class="input-group input">
+            <input v-focus
+              type="number"
+              max="2147483647"
+              min="1"
+              @keyup.enter="submit"
+              v-model.trim="time">
+            <select class="right" v-model="unit" :aria-label="$t('time.unit')">
+              <option value="seconds">{{ $t('time.seconds') }}</option>
+              <option value="minutes">{{ $t('time.minutes') }}</option>
+              <option value="hours">{{ $t('time.hours') }}</option>
+              <option value="days">{{ $t('time.days') }}</option>
+            </select>
+        </div>
+        <p>{{ $t('prompts.optionalPassword') }}</p>
+        <input class="input input--block" type="password" v-model.trim="password">
+      </div>
 
-        <li v-if="!hasPermanent">
-          <div>
-            <input type="password" :placeholder="$t('prompts.optionalPassword')" v-model="passwordPermalink">
-            <a @click="getPermalink" :aria-label="$t('buttons.permalink')">{{ $t('buttons.permalink') }}</a>
-          </div>
-        </li>
-
-        <li>
-          <input v-focus
-            type="number"
-            max="2147483647"
-            min="0"
-            @keyup.enter="submit"
-            v-model.trim="time">
-          <select v-model="unit" :aria-label="$t('time.unit')">
-            <option value="seconds">{{ $t('time.seconds') }}</option>
-            <option value="minutes">{{ $t('time.minutes') }}</option>
-            <option value="hours">{{ $t('time.hours') }}</option>
-            <option value="days">{{ $t('time.days') }}</option>
-          </select>
-          <input type="password" :placeholder="$t('prompts.optionalPassword')" v-model="password">
-          <button class="action"
-            @click="submit"
-            :aria-label="$t('buttons.create')"
-            :title="$t('buttons.create')"><i class="material-icons">add</i></button>
-        </li>
-      </ul>
-    </div>
-
-    <div class="card-action">
-      <button class="button button--flat"
-        @click="$store.commit('closeHovers')"
-        :aria-label="$t('buttons.close')"
-        :title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
-    </div>
+      <div class="card-action">
+        <button class="button button--flat button--grey"
+          @click="() => switchListing()"
+          :aria-label="$t('buttons.cancel')"
+          :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
+        <button class="button button--flat button--blue"
+          @click="submit"
+          :aria-label="$t('buttons.share')"
+          :title="$t('buttons.share')">{{ $t('buttons.share') }}</button>
+      </div>
+    </template>
   </div>
 </template>
 
@@ -75,11 +96,10 @@ export default {
     return {
       time: '',
       unit: 'hours',
-      hasPermanent: false,
       links: [],
       clip: null,
       password: '',
-      passwordPermalink: ''
+      listing: true
     }
   },
   computed: {
@@ -104,11 +124,8 @@ export default {
       this.links = links
       this.sort()
 
-      for (let link of this.links) {
-        if (link.expire === 0) {
-          this.hasPermanent = true
-          break
-        }
+      if (this.links.length == 0) {
+        this.listing = false
       }
     } catch (e) {
       this.$showError(e)
@@ -125,22 +142,25 @@ export default {
   },
   methods: {
     submit: async function () {
-      if (!this.time) return
+      let isPermanent = !this.time || this.time == 0
 
       try {
-        const res = await api.create(this.url, this.password, this.time, this.unit)
+        let res = null
+
+        if (isPermanent) {
+          res = await api.create(this.url, this.password)
+        } else {
+          res = await api.create(this.url, this.password, this.time, this.unit)
+        }
+
         this.links.push(res)
         this.sort()
-      } catch (e) {
-        this.$showError(e)
-      }
-    },
-    getPermalink: async function () {
-      try {
-        const res = await api.create(this.url, this.passwordPermalink)
-        this.links.push(res)
-        this.sort()
-        this.hasPermanent = true
+
+        this.time = ''
+        this.unit = 'hours'
+        this.password = ''
+
+        this.listing = true
       } catch (e) {
         this.$showError(e)
       }
@@ -149,8 +169,11 @@ export default {
       event.preventDefault()
        try {
         await api.remove(link.hash)
-        if (link.expire === 0) this.hasPermanent = false
         this.links = this.links.filter(item => item.hash !== link.hash)
+
+        if (this.links.length == 0) {
+          this.listing = false
+        }
       } catch (e) {
         this.$showError(e)
       }
@@ -167,6 +190,13 @@ export default {
         if (b.expire === 0) return 1
         return new Date(a.expire) - new Date(b.expire)
       })
+    },
+    switchListing () {
+      if (this.links.length == 0 && !this.listing) {
+        this.$store.commit('closeHovers')
+      }
+
+      this.listing = !this.listing
     }
   }
 }
diff --git a/frontend/src/css/_share.css b/frontend/src/css/_share.css
index c043a73c..a5f2d35f 100644
--- a/frontend/src/css/_share.css
+++ b/frontend/src/css/_share.css
@@ -70,9 +70,4 @@
   padding: .5em;
   text-align: center;
   animation: .2s opac forwards;
-}
-
-.share__promt__card {
-  max-width: max-content !important;
-  width: auto !important;
-}
+}
\ No newline at end of file
diff --git a/frontend/src/css/dashboard.css b/frontend/src/css/dashboard.css
index b29e907f..52a8d41e 100644
--- a/frontend/src/css/dashboard.css
+++ b/frontend/src/css/dashboard.css
@@ -226,6 +226,18 @@ table tr>*:last-child {
   opacity: 1;
 }
 
+.card#share .input-group {
+  display: flex;
+}
+
+.card#share .input-group * {
+  border: none;
+}
+
+.card#share .input-group input {
+  flex: 1;
+}
+
 .overlay {
   background-color: rgba(0, 0, 0, 0.5);
   position: fixed;
diff --git a/http/share.go b/http/share.go
index 9ee28587..d813500e 100644
--- a/http/share.go
+++ b/http/share.go
@@ -6,7 +6,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"path"
 	"sort"
 	"strconv"
 	"strings"
@@ -91,17 +90,6 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
 		defer r.Body.Close()
 	}
 
-	if body.Expires == "" {
-		var err error
-		s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID)
-		if err == nil {
-			if _, err := w.Write([]byte(path.Join(d.server.BaseURL, "/share/", s.Hash))); err != nil {
-				return http.StatusInternalServerError, err
-			}
-			return 0, nil
-		}
-	}
-
 	bytes := make([]byte, 6)
 	_, err := rand.Read(bytes)
 	if err != nil {