Skip to content

Commit

Permalink
new image uploader, link previews refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
tempe-techie committed Dec 1, 2023
1 parent f61b4d9 commit 21dd0b8
Show file tree
Hide file tree
Showing 29 changed files with 1,219 additions and 498 deletions.
9 changes: 6 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
TENOR_KEY=
WEB3_STORAGE_KEY=
RPC_CUSTOM=
FILE_UPLOAD_SERVICE=
LINK_PREVIEW_SERVICE=
RPC_CUSTOM=
SPHERON_BUCKET_NAME=
SPHERON_STORAGE_TOKEN=
TENOR_KEY=
9 changes: 4 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
node_modules
*.log*
.nuxt
.netlify
.nitro
.nuxt
.cache
.output
.env
dist

# Local Netlify folder
.netlify
.vercel
dist
59 changes: 47 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
# FLR Chat

FLR Chat is a Web3 Social frontend website based on the Iggy Social template. It uses [Orbis SDK](https://github.com/OrbisWeb3/orbis-sdk) and Ceramic Network in the background.
FLR Chat is a Web3 Social frontend website based on the Iggy Social framework. It uses [Orbis SDK](https://github.com/OrbisWeb3/orbis-sdk) and Ceramic Network in the background.

Link: https://flr.chat

What's included:
## Delete mirror.yml in the .github folder

- [Orbis SDK](https://github.com/OrbisWeb3/orbis-sdk)
- [Nuxt 3](https://v3.nuxtjs.org/)
- [Vue Dapp](https://vue-dapp-docs.netlify.app/)
- [Ethers 5](https://ethers.org/)
- [Pinia](https://pinia.vuejs.org/)
- [Vue Toastification](https://github.com/Maronato/vue-toastification/tree/next)
The mirror.yml file is just for the purpose of mirroring this repo to other git servers (for backup reasons). You don't need this in your cloned project.

Build.yml is optional, it builds the projects, and stores the built code on the `build` branch. You can then use this branch for cheap deployment on 4everland (for example) - see instructions below.

## .env

Expand All @@ -27,17 +24,49 @@ Make sure to use the the `npm run generate` command instead of `npm run build` f

If you want to use optional features such as GIFs and image upload, make sure to enter proper environment variables (see `.env.example`).

Make sure to also select the proper serverless functions services in your environment variables, for example:

```bash
FILE_UPLOAD_SERVICE=netlify
LINK_PREVIEW_SERVICE=netlify
```

You can also set these in the Nuxt config file (`nuxt.config.ts`).

### 4everland

[4everland](https://4everland.org/) is a decentralized hosting provider which stores your website on IPFS.

If you have your code on GitHub, the `build.yml` script will build your app via GitHub Actions and create a `build` branch.

Make sure you add all the necessary env vars (tenor etc.) to the organization variables for actions on GitHub.

Also make sure you have Workflow permissions on the organization level on GitHub set to read & write.

Then, when you create a project on 4everland, make sure you select the `build` branch.

And in the build section delete the command and set build folder to empty (or `./`). The preset can be set to `Other`. No install command is needed either.

![](https://bafkreid6mzglrk5hklraua267sker6gqsfpy2ezmjj7yc2oqmx2arbynru.ipfs.w3s.link)

## GIFs (Tenor)

If you want to have GIF search implemented, create your own Tenor API Key on Google Cloud Console. Follow the instructions here: https://developers.google.com/tenor/guides/quickstart.

Then enter the key in environment variables (`TENOR_KEY`).

## Image upload (Web3 Storage)
## Image upload (Spheron/IPFS)

To support image uploads on IPFS please create a key/token on Spheron Storage: https://app.spheron.network/#/storage

To support image uploads on IPFS please create an API key on Web3 Storage: https://web3.storage/
Then add this key (and your bucket ID/name) to your environment variables:

```bash
SPHERON_BUCKET_NAME=
SPHERON_STORAGE_TOKEN=
```

Then enter the key in environment variables (`WEB3_STORAGE_KEY`).
Image uploads via Spheron work only if you have Netlify/Vercel background functions enabled (see `netlify/functions/imageUploader.js`).

## Customize

Expand Down Expand Up @@ -68,6 +97,12 @@ Start the development server on http://localhost:3000
npm run dev
```

Or run Netlify dev server on http://localhost:8888 (to get link previews):

```bash
netlify dev
```

## Production

Build the application for production:
Expand All @@ -90,4 +125,4 @@ Orbis test group:

```bash
https://app.orbis.club/group/kjzl6cwe1jw145e1i1agcrjp9375sjpyyk7imu281koehrpve0pr46lvr5e9xco
```
```
3 changes: 3 additions & 0 deletions api/_readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vercel serverless function

This folder contains serverless functions for Vercel.
25 changes: 25 additions & 0 deletions api/imageUploader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { SpheronClient, ProtocolEnum } = require("@spheron/storage");

export default async function handler(request, response) {
try {
const bucketName = process.env.SPHERON_BUCKET_NAME; // enter bucket name in environment variables
const token = process.env.SPHERON_STORAGE_TOKEN; // add spheron storage token in environment variables

const protocol = ProtocolEnum.IPFS;

const client = new SpheronClient({ token });

const { uploadToken } = await client.createSingleUploadToken({
name: bucketName,
protocol,
});

return response.status(200).json({
data: uploadToken
});

} catch (error) {
console.error(error);
next(error);
}
}
12 changes: 12 additions & 0 deletions api/linkPreviews.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { fetchMetadata } = require('../utils/linkPreviewUtils');

export default async function handler(request, response) {
const url = request.query.url;

const { metadata, status } = await fetchMetadata(url);

return response.status(status).json({
data: metadata
});

};
70 changes: 70 additions & 0 deletions components/VerifyAccountOwnership.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<template>
<!-- Verify Account Ownership modal -->
<div class="modal fade" id="verifyAccountModal" tabindex="-1" aria-labelledby="verifyAccountModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Verify Account Ownership</h5>
<button id="closeVerifyAccountModal" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true"></span>
</button>
</div>
<div class="modal-body p-3 mb-3">

<p>
Verify that you really own this account/wallet. This will allow you to use chat, change profile image, and set some other settings.
</p>

<button class="btn btn-primary" @click="connectToOrbis">
Verify your account
</button>

</div>
</div>
</div>
</div>
<!-- END Connect Wallet modal -->
</template>

<script>
import { useUserStore } from '~/store/user';
import { useToast } from "vue-toastification/dist/index.mjs";
export default {
name: "VerifyAccountOwnership",
methods: {
async connectToOrbis() {
let provider = this.$getFallbackProvider(this.$config.supportedChainId);
let res = await this.$orbis.connect_v2({
provider: provider.provider,
lit: false
});
/** Check if connection is successful or not */
if(res.status == 200) {
this.userStore.setIsConnectedToOrbis(true);
if (this.$orbis.session) {
this.userStore.setDid(this.$orbis.session.did._id);
this.userStore.setDidParent(this.$orbis.session.did._parentId);
}
document.getElementById('closeVerifyAccountModal').click();
} else {
console.log("Error verifying account: ", res);
this.toast(res.result, {type: "error"});
}
},
},
setup() {
const userStore = useUserStore();
const toast = useToast();
return { userStore, toast };
},
}
</script>
27 changes: 20 additions & 7 deletions components/chat/ChatFeed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,25 @@
-->

<!-- Upload IMG button -->
<Web3StorageImageUpload
v-if="isActivated && $config.web3storageKey !== '' && userStore.getIsConnectedToOrbis && isSupportedChain && hasDomainOrNotRequired"
@insertImage="insertImage"
buttonText="IMG"
cls="btn btn-outline-primary me-2 mt-2 btn-sm"
<button
v-if="isActivated && $config.fileUploadEnabled !== '' && userStore.getIsConnectedToOrbis && isSupportedChain && hasDomainOrNotRequired"
class="btn btn-outline-primary me-2 mt-2 btn-sm"
data-bs-toggle="modal" :data-bs-target="'#fileUploadModal'+$.uid"
>
<i class="bi bi-file-earmark-image-fill"></i>
IMG
</button>

<!-- Upload Image Modal -->
<FileUploadModal
v-if="userStore.getIsConnectedToOrbis"
@processFileUrl="insertImage"
title="Upload image"
infoText="Upload an image."
:componentId="$.uid"
:maxFileSize="$config.fileUploadSizeLimit"
/>
<!-- END Upload Image Modal -->

<!-- Emoji Picker -->
<EmojiPicker
Expand Down Expand Up @@ -147,7 +160,7 @@ import ConnectWalletButton from "~/components/ConnectWalletButton.vue";
import SwitchChainButton from "~/components/SwitchChainButton.vue";
import TenorGifSearch from "~/components/tenor/TenorGifSearch.vue";
import TenorStickerSearch from "~/components/tenor/TenorStickerSearch.vue";
import Web3StorageImageUpload from "~/components/storage/Web3StorageImageUpload.vue";
import FileUploadModal from "~/components/storage/FileUploadModal.vue";
import EmojiPicker from '~/components/EmojiPicker.vue'
import 'emoji-mart-vue-fast/css/emoji-mart.css'
Expand All @@ -168,10 +181,10 @@ export default {
components: {
ChatPost,
ConnectWalletButton,
FileUploadModal,
SwitchChainButton,
TenorGifSearch,
TenorStickerSearch,
Web3StorageImageUpload,
EmojiPicker
},
Expand Down
2 changes: 2 additions & 0 deletions components/chat/ChatPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ export default {
if (this.$config.linkPreviews === "netlify") {
fetcherService = thisAppUrl + "/.netlify/functions/linkPreviews?url=" + this.firstLink;
} else if (this.$config.linkPreviews === "vercel") {
fetcherService = thisAppUrl + "/api/linkPreviews?url=" + this.firstLink;
} else if (this.$config.linkPreviews === "microlink") {
fetcherService = "https://api.microlink.io/?url=" + this.firstLink;
}
Expand Down
38 changes: 25 additions & 13 deletions components/nft/collection/AddImageToCollectionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,26 @@

<div class="modal-body">

<div class="mt-4">
<label :for="'input-'+componentId" class="form-label">
<strong>
Add this image URL to collection:
</strong>
</label>
<div class="mt-2">
<div v-if="!imageUrl && $config.fileUploadEnabled">
<p>Upload new image (and then click Submit below):</p>

<FileUploadInput
btnCls="btn btn-primary"
:maxFileSize="$config.fileUploadSizeLimit"
@processUploadedFileUrl="insertImageLink"
/>


<p class="mt-3">Or paste image link here:</p>
</div>

<p v-if="!$config.fileUploadEnabled">Paste image link here:</p>

<input v-model="imageUrl" type="text" class="form-control" :id="'input-'+componentId">
<input v-model="imageUrl" type="text" class="form-control" id="addImageToCollectionInput" />

<div v-if="imageUrl" class="mt-3">
<img :src="imageUrl" class="img-thumbnail img-fluid" style="max-width: 100px;" />
<img :src="imageUrl" :key="imageUrl" class="img-thumbnail img-fluid" style="max-width: 100px;" />
<br />
<small>If image didn't appear above, then something is wrong with the link you added.</small>
</div>
Expand All @@ -28,11 +37,9 @@
</div>

<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>

<button @click="addNewImage" type="button" class="btn btn-primary" :disabled="!imageUrl || waiting">
<span v-if="waiting" class="spinner-border spinner-border-sm mx-1" role="status" aria-hidden="true"></span>
Submit
Submit to blockchain
</button>
</div>
</div>
Expand All @@ -45,10 +52,12 @@ import { ethers } from 'ethers';
import { useEthers } from 'vue-dapp';
import { useToast } from "vue-toastification/dist/index.mjs";
import WaitingToast from "~/components/WaitingToast";
import FileUploadInput from '~/components/storage/FileUploadInput.vue';
export default {
name: 'AddImageToCollectionModal',
props: ["cAddress", "mdAddress"],
components: { FileUploadInput },
data() {
return {
Expand Down Expand Up @@ -119,8 +128,7 @@ export default {
try {
let extractMessage = e.message.split("reason=")[1];
extractMessage = extractMessage.split(", method=")[0];
extractMessage = extractMessage.replace('"', "");
extractMessage = extractMessage.replace('"', "");
extractMessage = extractMessage.replace(/"/g, "");
extractMessage = extractMessage.replace('execution reverted:', "Error:");
console.log(extractMessage);
Expand All @@ -133,6 +141,10 @@ export default {
this.waiting = false;
}
},
insertImageLink(fileUrl) {
this.imageUrl = fileUrl;
},
},
setup() {
Expand Down
Loading

0 comments on commit 21dd0b8

Please sign in to comment.