Bläddra i källkod

Add some features, remove some code, fix some bugs

wip/alt-interface
Jared 2 år sedan
förälder
incheckning
543b149529
11 ändrade filer med 136 tillägg och 55 borttagningar
  1. +25
    -0
      src/App.vue
  2. +2
    -1
      src/api/types.ts
  3. Binär
      src/assets/icons8-michigan-50.png
  4. +1
    -1
      src/components/FundLink.vue
  5. +0
    -4
      src/lib/helpers.ts
  6. +17
    -2
      src/router/index.ts
  7. +14
    -12
      src/views/AddFundView.vue
  8. +59
    -33
      src/views/FundView.vue
  9. +6
    -1
      src/views/HomeView.vue
  10. +1
    -1
      src/views/RegisterView.vue
  11. +11
    -0
      vue.config.js

+ 25
- 0
src/App.vue Visa fil

@@ -43,6 +43,12 @@
</Suspense>
</RouterView>
</div>

<footer>
<div>
Proudly made in Michigan <div class="michigan-icon"></div>
</div>
</footer>
</template>

<script setup lang="ts">
@@ -85,4 +91,23 @@ body
min-height 100vh
color #e8dbca
background-color #313538

footer
color #707070
padding 12px
margin-top 10px

& *
vertical-align middle
text-align center

.michigan-icon
display inline-block
width 28px
height 28px
background-image url("./assets/icons8-michigan-50.png")
background-repeat no-repeat
background-position center
background-size 28px
margin-left 4px
</style>

+ 2
- 1
src/api/types.ts Visa fil

@@ -61,10 +61,11 @@ export interface FundInfo {
id: number;
asset: string;
fundWallet: string;
fundSecret: string;
sellingWallet: string;
issuerWallet: string;
memo: string;
price: number;
amountAvailable: number;
amountGoal: number;
minContribution: number;
title: string;


Binär
src/assets/icons8-michigan-50.png Visa fil

Före Efter
Bredd: 50  |  Höjd: 50  |  Storlek: 892 B

+ 1
- 1
src/components/FundLink.vue Visa fil

@@ -12,7 +12,7 @@
</li>
<li class="is-size-7 is-inline-block px-2">
<span class="stellar-icon-base goal"></span>
<span class="fund-label">{{ props.fund.amountGoal.toLocaleString() }}</span>
<span class="fund-label">{{ props.fund.amountAvailable.toLocaleString() }}</span>
</li>
<li class="is-size-7 is-inline-block px-2">
<span class="stellar-icon-base memo"></span>


+ 0
- 4
src/lib/helpers.ts Visa fil

@@ -1,6 +1,2 @@
import { useRouter } from 'vue-router';

const router = useRouter();

export const truncateWallet: (wallet: string, preDigits: number, postDigits: number | undefined) => string = (wallet: string, preDigits: number, postDigits = preDigits) => `${wallet.slice(0, preDigits)}...${wallet.slice(-(postDigits + 1), -1)}`;
export const isNumber = (s: string) => /^[0-9]+$/.test(s);

+ 17
- 2
src/router/index.ts Visa fil

@@ -5,11 +5,16 @@ import {
} from 'vue-router';
import RegisterView from '@/views/RegisterView.vue';
import LoginView from '@/views/LoginView.vue';
import { Privileges } from '@/api/types';
import {
Privileges,
SuccessResponse,
} from '@/api/types';
import HomeView from '@/views/HomeView.vue';
import FundView from '@/views/FundView.vue';
import AddFundView from '@/views/AddFundView.vue';
import hasPermission from '@/lib/auth';
import SignetRequestController from '@/api/requests';
import store from '@/store';

const routes: Array<RouteRecordRaw> = [
{
@@ -36,6 +41,11 @@ const routes: Array<RouteRecordRaw> = [
component: RegisterView,
meta: {
requiredRights: Privileges.AdminPlus,
accessible: async () => {
const controller = new SignetRequestController(store.getters.getToken);
const canProceed = await controller.post<SuccessResponse, null>('/UsersExist', null);
return canProceed?.success;
},
title: 'Register',
},
},
@@ -58,7 +68,12 @@ const router = createRouter({
router.beforeEach(async (to, from, next) => {
document.title = `Beignet - ${to.meta.title}`;

if (hasPermission(to.meta.requiredRights as number)) {
const requiredRights = to.meta.requiredRights as number | undefined;
const accessible = to.meta.accessible as (() => SuccessResponse) | undefined;
const allowed = requiredRights ? hasPermission(requiredRights)
|| (accessible && !accessible().success) : true;

if (allowed) {
next();
} else {
next('/');


+ 14
- 12
src/views/AddFundView.vue Visa fil

@@ -22,7 +22,7 @@
</div>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
placeholder="Fund Secret" aria-label="Fund Wallet" v-model="fundSecret">
placeholder="Selling Wallet" aria-label="Selling Wallet" v-model="sellWallet">
</div>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
@@ -33,16 +33,17 @@
<div class="title is-5 has-text-white-ter">Fund</div>
<div class="control my-2 is-flex is-justify-content-space-between">
<input class="input is-normal mr-1 has-background-white has-text-black" type="text"
placeholder="Asset" aria-label="Asset" v-model="asset">
<input class="input is-normal ml-1 has-background-white has-text-black" type="text"
placeholder="Asset Code" aria-label="Asset" v-model="asset">
<input class="input is-normal mx-1 has-background-white has-text-black" type="text"
placeholder="Memo" aria-label="Memo" v-model="memo">
</div>
<div class="control my-2 is-flex is-justify-content-space-between">
<input class="input is-normal mr-1 has-background-white has-text-black" type="number"
placeholder="Min Contribution" aria-label="Asset" v-model="minContribution">
<input class="input is-normal ml-1 has-background-white has-text-black" type="number"
placeholder="Amount Goal" aria-label="Memo" v-model="amtGoal">
placeholder="Min Contribution" aria-label="Asset" v-model="minContribution">
</div>
<!-- <div class="control my-2 is-flex is-justify-content-space-between">-->

<!-- <input class="input is-normal ml-1 has-background-white has-text-black" type="number"-->
<!-- placeholder="Amount Goal" aria-label="Memo" v-model="amtGoal">-->
<!-- </div>-->
</section>
<section class="section px-0 py-4">
<div class="title is-5 has-text-white-ter">Bonus Structure</div>
@@ -81,12 +82,13 @@ const controller = new SignetRequestController(store.getters.getToken);
const title = ref('');
const description = ref('');
const fundWallet = ref('');
const fundSecret = ref('');
const sellWallet = ref('');
// const fundSecret = ref('');
const issuerWallet = ref('');
const asset = ref('');
const memo = ref('');
const minContribution = ref(undefined as number | undefined);
const amtGoal = ref(undefined as number | undefined);
// const amtGoal = ref(undefined as number | undefined);

const bonuses = ref([] as Bonus[]);
const saveBonuses = (evt: Bonus[]) => {
@@ -100,10 +102,10 @@ const submit = async () => {
const resp = await controller.post<SuccessResponse, Partial<FundInfo>>('CreateRewardFund', {
asset: asset.value,
fundWallet: fundWallet.value,
fundSecret: fundSecret.value,
sellingWallet: sellWallet.value,
issuerWallet: issuerWallet.value,
memo: memo.value,
amountGoal: amtGoal.value as number,
// amountGoal: amtGoal.value as number,
minContribution: minContribution.value as number,
title: title.value,
description: description.value,


+ 59
- 33
src/views/FundView.vue Visa fil

@@ -29,14 +29,6 @@
<div class="title is-size-4 has-text-grey-dark has-text-centered">
Tracker
</div>
<div class="has-text-centered is-size-4 has-text-grey-dark mb-3">
<span class="total-label is-size-3 pr-2 has-text-weight-light">
Total
</span>
<span class="pl-3 has-text-weight-bold">
{{ fund.total.amountHeld.toLocaleString() }} XLM
</span>
</div>
<div class="level" v-if="fund.fundInfo.bonuses.length > 0">
<div class="level-item has-text-centered"
v-for="bonus in fund.fundInfo.bonuses.sort((v1, v2) => v1.goal - v2.goal)"
@@ -45,14 +37,14 @@
<div>
<p
class="heading"
:class="fund.total.amountHeld >= bonus.goal
:class="amountHeld >= bonus.goal
? 'has-text-success' : 'has-text-grey-dark'"
>
{{ bonus.goal.toLocaleString() }} XLM
</p>
<p
class="title"
:class="fund.total.amountHeld >= bonus.goal
:class="amountHeld >= bonus.goal
? 'has-text-success' : 'has-text-grey-dark'"
>
{{ bonus.percent }}%
@@ -61,6 +53,31 @@
</div>
</div>
</div>
<div
class="is-flex
is-flex-direction-row
is-justify-content-space-around
is-size-4
has-text-white
mb-3"
>
<div class="total">
<span class="total-label is-size-3 pr-2 has-text-weight-light">
Raised
</span>
<span class="pl-3 has-text-weight-bold">
{{ amountHeld.toLocaleString() }} XLM
</span>
</div>
<div class="remaining">
<span class="remaining-label is-size-3 pr-2 has-text-weight-light">
Remaining
</span>
<span class="pl-3 has-text-weight-bold">
{{ amountAvailable.toLocaleString() }} XLM
</span>
</div>
</div>
</section>
<section class="section is-small">
<div class="title is-size-4 has-text-white-ter has-text-centered">
@@ -78,6 +95,7 @@
<button
class="button is-primary"
:class="requesting ? 'is-loading' : ''"
:disabled="amt > amountAvailable"
@click="makeContribution"
>Submit</button>
</div>
@@ -143,7 +161,7 @@
<div class="box is-flex is-flex-direction-row is-justify-content-space-between">
<div class="my-auto">
<label class="checkbox" for="delete-confirm">
<input type="checkbox" id="delete-confirm" v-model="allowDelete"> Delete
<input type="checkbox" id="delete-confirm" v-model="allowDelete"> Close
</label>
</div>
<div>
@@ -152,7 +170,7 @@
:disabled="!allowDelete"
@click="deleteFund"
>
Delete
Close
</button>
</div>
</div>
@@ -254,7 +272,7 @@ fundDetails.value = [
},
{
title: 'Goal',
val: `${fund.value.fundInfo.amountGoal.toLocaleString()}`,
val: `${fund.value.fundInfo.amountAvailable.toLocaleString()}`,
},
{
title: 'Memo',
@@ -270,21 +288,27 @@ if (fund.value.contributions.dates) {
const reward = ref(0);
const maxBonus = ref(0);
const bonus = ref(undefined as Bonus | undefined);
const achievedBonuses = fund.value.fundInfo.bonuses.filter(
(b) => {
if (!fund.value) throw new Error('Fund not found');
return b.goal && fund.value.total.amountHeld >= b.goal;
},
);
if (achievedBonuses.length > 0) {
maxBonus.value = Math.max(...achievedBonuses.map((b) => b.goal ?? -1));
bonus.value = achievedBonuses.find((b) => b.goal === maxBonus.value);
if (!Object.entries(bonus).length) throw new Error('Something went wrong');
}
const amountHeld = ref(fund.value.total.amountHeld);
const amountAvailable = ref(fund.value.fundInfo.amountAvailable);

const calculateReward = (bought: number) => {
const getCurrentBonus = () => {
if (!fund.value) throw new Error('Fund not found!');
const achievedBonuses = fund.value.fundInfo.bonuses.filter(
(b) => {
if (!fund.value) throw new Error('Fund not found');
return b.goal && fund.value.total.amountHeld >= b.goal;
},
);
if (achievedBonuses.length > 0) {
if (!bonus.value || !bonus.value.percent) throw new Error('Something went wrong');
maxBonus.value = Math.max(...achievedBonuses.map((b) => b.goal ?? -1));
bonus.value = achievedBonuses.find((b) => b.goal === maxBonus.value);
if (!Object.entries(bonus).length) throw new Error('Something went wrong');
}
};

const calculateReward = (bought: number) => {
if (bonus.value) {
if (!bonus.value.percent) throw new Error('Bonus did not have percent for some reason');
reward.value = bought + bought * (bonus.value.percent / 100);
} else {
reward.value = bought;
@@ -377,9 +401,14 @@ const {

watch(data, (newVal) => {
if (!fund.value) throw new Error('Fund not found');
getCurrentBonus();
if (status.value === 'OPEN') {
const v = JSON.parse(newVal.trim()) as Contribution;
v.CreatedAt = luxon.DateTime.now().toISO();
const formattedDate = formatDate(v.CreatedAt);
if (!selectableDates.value.includes(formattedDate)) {
selectableDates.value.push(formattedDate);
}
if (enableConsolidation.value && contributions.value
&& contributions.value.map((c: Contribution) => c.wallet).includes(v.wallet)) {
const hasContribution = contributions.value.find((c: Contribution) => c.wallet === v.wallet);
@@ -388,19 +417,16 @@ watch(data, (newVal) => {
} else {
contributions.value.splice(0, 0, v);
offset.value += 1;
const formattedDate = formatDate(v.CreatedAt);
if (!selectableDates.value.includes(formattedDate)) {
selectableDates.value.push(formattedDate);
}
}
fund.value.total.amountHeld += v.amount;
amountHeld.value += v.amount;
amountAvailable.value -= v.amount;
}
});

const requesting = ref(false);
const makeContribution = async () => {
if (!fund.value) throw new Error('Fund not found');
if (!requesting.value && pk.value && amt.value) {
if (!requesting.value && pk.value && amt.value && amt.value <= amountAvailable.value) {
requesting.value = true;
await controller.post<SuccessResponse, ContributeRequest>('Contribute', {
privateKey: pk.value,
@@ -428,7 +454,7 @@ const makeContribution = async () => {
vertical-align: bottom;
text-overflow: ellipsis;

.total-label
.total-label, .remaining-label
border-right 1px solid #8f8f8f
font-variant all-petite-caps



+ 6
- 1
src/views/HomeView.vue Visa fil

@@ -1,13 +1,18 @@
<template>
<div class="container is-max-desktop">
<section class="section is-small px-0">
<div class="container-grid">
<div class="container-grid" v-if="rewardFunds">
<template v-for="fund in rewardFunds" v-bind:key="fund.id">
<RouterLink :to="`/fund/${fund.id}`">
<FundLink :fund="fund"/>
</RouterLink>
</template>
</div>
<div v-else>
<div class="has-text-centered is-size-4">
No group funds yet!
</div>
</div>
</section>
</div>
</template>


+ 1
- 1
src/views/RegisterView.vue Visa fil

@@ -40,7 +40,7 @@ const submit = async () => {
if (!resp) throw new Error('Could not get response from registration');
success.value = resp.success;
if (success.value) {
await router.push('/login');
await router.push('/');
}
};
</script>


+ 11
- 0
vue.config.js Visa fil

@@ -1,5 +1,16 @@
const { defineConfig } = require('@vue/cli-service');

module.exports = defineConfig({
devServer: {
proxy: {
'^/api': {
target: 'http://localhost:7300',
changeOrigin: true,
secure: false,
pathRewrite: { '^/api': '' },
logLevel: 'debug',
},
},
},
transpileDependencies: true,
});

Laddar…
Avbryt
Spara