瀏覽代碼

Queue editor sends new order to server

master
Jared 1 年之前
父節點
當前提交
24d9a78182
共有 11 個檔案被更改,包括 261 行新增57 行删除
  1. +2
    -2
      src/App.vue
  2. +13
    -4
      src/api/composed.ts
  3. +32
    -6
      src/api/types.ts
  4. +38
    -17
      src/components/EditQueue.vue
  5. +21
    -7
      src/components/FundLink.vue
  6. +55
    -4
      src/router/index.ts
  7. +1
    -0
      src/views/AddFundView.vue
  8. +39
    -0
      src/views/AdminDashboardView.vue
  9. +28
    -12
      src/views/AdminView.vue
  10. +8
    -5
      src/views/FundView.vue
  11. +24
    -0
      src/views/ModifyQueueView.vue

+ 2
- 2
src/App.vue 查看文件

@@ -19,8 +19,8 @@
</RouterLink>
</div>
<div v-else>
<RouterLink to="/addfund" class="button is-primary">
Add Fund
<RouterLink to="/admin/dashboard" class="button is-primary">
Admin
</RouterLink>
<RouterLink to="/register" class="button is-white">
Register


+ 13
- 4
src/api/composed.ts 查看文件

@@ -7,6 +7,7 @@ import {
CreateQueueRequest,
CreateQueueResponse,
CreateRewardFundRequest,
EditQueueRequest,
GetBalanceRequest,
GetBalanceResponse,
GetContributionsRequest,
@@ -19,6 +20,9 @@ import {
GetRewardFundsRequest,
GetRewardFundsResponse,
LoginResponse,
NearlyCompleteFundsRequest,
NearlyCompleteFundsResponse,
QueueMember,
SuccessResponse,
} from '@/api/types';

@@ -49,8 +53,7 @@ export const createRewardFund = (
issuerWallet: string,
memo: string,
minContribution: number,
title: string,
description: string,
telegramLink: string,
bonuses: Bonus[],
queueID?: number | null | undefined,
) => controller.post<SuccessResponse, CreateRewardFundRequest>('CreateRewardFund', {
@@ -60,8 +63,7 @@ export const createRewardFund = (
issuerWallet,
memo,
minContribution,
title,
description,
telegramLink,
bonuses,
queueID,
});
@@ -103,3 +105,10 @@ export const contribute = (privateKey: string, amount: number, rewardFund: numbe
amount,
rewardFund,
});

export const getNearlyCompletedFunds = (threshold: number) => controller.post<NearlyCompleteFundsResponse, NearlyCompleteFundsRequest>('NearlyCompleteFunds', { threshold });

export const reorderQueue = (queueID: number, fundOrders: QueueMember[]) => controller.post<SuccessResponse, EditQueueRequest>('EditQueue', {
queueID,
fundOrders,
});

+ 32
- 6
src/api/types.ts 查看文件

@@ -28,8 +28,7 @@ export interface RewardFund {
amountGoal: number;
minContribution: number;
contributions: Contribution[] | null;
title: string;
description: string;
telegramLink: string;
}

export interface Queue {
@@ -37,6 +36,12 @@ export interface Queue {
name: string;
}

export interface QueueMember {
id?: number;
asset: string;
order: number;
}

export interface CreateQueueRequest {
name: string;
}
@@ -70,8 +75,7 @@ export interface CreateRewardFundRequest {
issuerWallet: string;
memo: string;
minContribution: number;
title: string;
description: string;
telegramLink: string;
queueID?: number | null;
bonuses: Bonus[];
}
@@ -87,8 +91,7 @@ export interface FundInfo {
amountAvailable: number;
amountGoal: number;
minContribution: number;
title: string;
description: string;
telegramLink: string;
bonuses: Bonus[];
queueID: number | null;
}
@@ -149,6 +152,24 @@ export interface Claims {
exp: number;
}

export interface NearlyCompletedFund {
id: number;
asset: string;
minContribution: number;
amountAvailable: number;
memo: string;
fundWallet: string;
raised: number;
}

export interface NearlyCompleteFundsRequest {
threshold: number;
}

export interface NearlyCompleteFundsResponse {
funds: NearlyCompletedFund[];
}

export interface GetContributionsRequest {
id: number;
offset: number;
@@ -162,3 +183,8 @@ export interface CloseRewardFundRequest {
id: number;
close: boolean;
}

export interface EditQueueRequest {
queueID: number;
fundOrders: QueueMember[];
}

+ 38
- 17
src/components/EditQueue.vue 查看文件

@@ -1,7 +1,18 @@
<template>
<div class="is-flex is-flex-direction-row is-justify-content-space-between">
<div class="select mr-1">
<div
class="is-flex is-flex-direction-row is-justify-content-space-between"
:class="props.orientation === 'horizontal'
? 'is-flex-direction-row'
: 'is-flex-direction-column'"
>
<div class="select"
:class="props.orientation === 'horizontal' ? 'mr-1' : 'mr-1 mb-2'"
:style="props.orientation === 'vertical'
? 'width: 28%; min-width: 180px; align-self: end'
: undefined"
>
<select
style="width: 100%"
ref="queueOptions"
v-model="queueSelection"
aria-label="Queue Selection"
@@ -14,6 +25,12 @@
</option>
</select>
</div>
<div v-if="queueSelection === undefined" class="is-flex-grow-1">
<div class="is-size-6 has-text-centered is-italic py-4">
Select an option from the menu
{{ props.orientation === 'vertical' ? 'above' : 'to the left' }}
</div>
</div>
<div v-if="queueSelection === -1" class="is-flex is-flex-direction-row is-flex-grow-1 ml-1">
<input
v-model="queueName"
@@ -32,7 +49,7 @@
:key="element.order"
>
<div class="is-flex is-flex-direction-row is-justify-content-space-between">
<div>{{ element.title }} ({{ element.asset }})</div>
<div>{{ element.asset }}</div>
<div>{{ element.order }}</div>
</div>
</div>
@@ -49,23 +66,22 @@ import {
} from 'vue';
import {
Queue,
QueueMember,
RewardFund,
} from '@/api/types';
import {
getQueueMembers,
getQueues,
reorderQueue,
} from '@/api/composed';
import { VueDraggableNext as Draggable } from 'vue-draggable-next';

interface QueueMember {
id?: number;
title: string;
asset: string;
order: number;
}
import { useDebounceFn } from '@vueuse/core';

// eslint-disable-next-line no-undef
const props = defineProps<{ newMember: RewardFund & { order: number; } }>();
const props = defineProps<{
newMember: RewardFund & { order: number; },
orientation: 'horizontal' | 'vertical'
}>();

// eslint-disable-next-line no-undef
const emits = defineEmits(['selected', 'created']);
@@ -75,13 +91,21 @@ const queueName = ref(undefined as string | undefined);
const queueMembers = ref(undefined as QueueMember[] | undefined);
const serverQueues = ref(0);

const reorder = () => {
const sendQueueOrder = useDebounceFn(async () => {
if (queueSelection.value && queueMembers.value) {
await reorderQueue(queueSelection.value, queueMembers.value);
}
}, 2000);

const reorder = async () => {
if (queueMembers.value) {
for (let i = 0; i < queueMembers.value.length; i += 1) {
if (queueMembers.value[i]) {
queueMembers.value[i].order = (i + 1);
}
}

await sendQueueOrder();
}
};

@@ -107,16 +131,14 @@ const populateQueueMembers = async (id: number) => {
const resp = await getQueueMembers(id) as { members: (RewardFund & { order: number; })[] };
queueMembers.value = resp?.members.map((m) => ({
id: m.id,
title: m.title,
asset: m.asset,
order: m.order,
}));
serverQueues.value = queueMembers.value.length;

if (queueMembers.value && props.newMember.title && props.newMember.asset) {
if (queueMembers.value && props.newMember.asset) {
const newMember = {
id: undefined,
title: props.newMember.title,
asset: props.newMember.asset,
order: queueMembers.value.length + 1,
};
@@ -134,10 +156,9 @@ watch(queueSelection, async (newValue) => {
const addedMember = computed(() => props.newMember);

watch(addedMember, (newVal) => {
if (newVal.title && newVal.asset) {
if (newVal.asset) {
const assembleNewMember = (order: number) => ({
id: undefined,
title: newVal.title,
asset: newVal.asset,
order,
});


+ 21
- 7
src/components/FundLink.vue 查看文件

@@ -1,8 +1,19 @@
<template>
<div class="card py-2 px-4 has-text-dark"
:style="generateBackgroundStyle(`${fund.asset} ${fund.title}`)">
<div class="is-size-2-desktop is-size-2-tablet is-size-3-mobile">
{{ fund.asset }}
<div class="is-flex
is-flex-direction-row
is-justify-content-space-between
is-size-2-desktop
is-size-2-tablet
is-size-3-mobile"
>
<div>
{{ fund.asset }}
</div>
<div v-if="props.aside">
{{ props.aside }}
</div>
</div>
<div>
<ul class="is-flex is-flex-direction-row is-justify-content-space-between">
@@ -30,15 +41,18 @@
</template>
<script setup lang="ts">
import { truncateWallet } from '@/lib/helpers';
import {
FundInfo,
} from '@/api/types';
import { FundInfo } from '@/api/types';
import { PropType } from 'vue';

// eslint-disable-next-line no-undef
const props = defineProps({ fund: Object as PropType<FundInfo> });
const props = defineProps({
fund: Object as PropType<FundInfo>,
aside: Object as PropType<string | number | undefined>,
});

const generateHue = (seed: string) => seed.split('').map((c) => c.charCodeAt(0)).reduce((v1, v2) => v1 + v2) % 256;
const generateHue = (seed: string) => seed.split('')
.map((c) => c.charCodeAt(0))
.reduce((v1, v2) => v1 + v2) % 256;

const generateBackgroundStyle = (hueSeed: string) => {
const hue = generateHue(hueSeed);


+ 55
- 4
src/router/index.ts 查看文件

@@ -14,6 +14,9 @@ import FundView from '@/views/FundView.vue';
import AddFundView from '@/views/AddFundView.vue';
import hasPermission from '@/lib/auth';
import SignetRequestController from '@/api/requests';
import AdminView from '@/views/AdminView.vue';
import ModifyQueueView from '@/views/ModifyQueueView.vue';
import AdminDashboardView from '@/views/AdminDashboardView.vue';

const routes: Array<RouteRecordRaw> = [
{
@@ -49,12 +52,60 @@ const routes: Array<RouteRecordRaw> = [
},
},
{
path: '/addfund',
name: 'addfund',
component: AddFundView,
path: '/admin',
name: 'admin',
component: AdminView,
redirect: '/admin/dashboard',
children: [
{
path: 'dashboard',
name: 'admindashboard',
component: AdminDashboardView,
meta: {
requiredRights: Privileges.Admin,
title: 'Admin',
},
},
{
path: 'addfund',
name: 'addfund',
component: AddFundView,
meta: {
requiredRights: Privileges.Admin,
title: 'Add Group Fund',
},
},
{
path: 'modifyfund',
name: 'modifyfund',
component: AddFundView,
meta: {
requiredRights: Privileges.Admin,
title: 'Add Group Fund',
},
},
{
path: 'addqueue',
name: 'addqueue',
component: AddFundView,
meta: {
requiredRights: Privileges.Admin,
title: 'Add Group Fund',
},
},
{
path: 'modifyqueue',
name: 'modifyqueue',
component: ModifyQueueView,
meta: {
requiredRights: Privileges.Admin,
title: 'Add Group Fund',
},
},
],
meta: {
requiredRights: Privileges.Admin,
title: 'Add Group Fund',
title: 'Administrator',
},
},
];


+ 1
- 0
src/views/AddFundView.vue 查看文件

@@ -49,6 +49,7 @@
<div class="title is-5 has-text-white-ter">Queue</div>
<EditQueue
:new-member="constructFund()"
orientation="horizontal"
@created="setQueueName"
@selected="setQueueSelection"
/>


+ 39
- 0
src/views/AdminDashboardView.vue 查看文件

@@ -0,0 +1,39 @@
<template>
<div class="container is-max-desktop">
<section class="section is-small px-0">
<template v-if="nearlyCompletedFunds.length > 0">
<div class="title is-4 has-text-white-ter has-text-centered">Nearly Completed Funds</div>
<div v-for="(fund, ind) in nearlyCompletedFunds" :key="ind">
<RouterLink :to="`/fund/${fund.id}`">
<FundLink :fund="fund" :aside="`${round(fund.raised/fund.amountAvailable*100)}%`"/>
</RouterLink>
</div>
</template>
</section>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { getNearlyCompletedFunds } from '@/api/composed';
import FundLink from '@/components/FundLink.vue';
import { NearlyCompletedFund } from '@/api/types';

const nearlyCompletedFunds = ref([] as NearlyCompletedFund[]);

const pctThreshold = 85;

const req = await getNearlyCompletedFunds(pctThreshold);
if (req?.funds) {
nearlyCompletedFunds.value = req?.funds;
}

const round = (float: number, digits = 1) => {
const factor = 10 ** digits;
return Math.round(float * factor) / factor;
};
</script>

<style scoped lang="stylus">

</style>

+ 28
- 12
src/views/AdminView.vue 查看文件

@@ -1,15 +1,17 @@
<template>
<!-- Unused -->
<div class="is-flex is-flex-direction-row">
<nav class="is-hidden-tablet-only is-hidden-mobile has-background-white-ter">
<div class="has-background-primary">
<span class="has-text-white has-text-weight-bold my-4 mx-2">Administration</span>
<nav class="is-hidden-tablet-only is-hidden-mobile">
<div class="mt-6">
<div>
<span class="has-text-white has-text-weight-bold my-4 mx-2">Administration</span>
</div>
<ul class="p-2">
<li v-for="(link, i) in links" v-bind:key="i">
<RouterLink :to="link.to" class="has-text-grey-light">{{ link.text }}</RouterLink>
</li>
</ul>
</div>
<ul class="p-2">
<li v-for="(link, i) in links" v-bind:key="i">
<RouterLink :to="link.to">{{ link.text }}</RouterLink>
</li>
</ul>
</nav>
<div class="container is-max-desktop">
<RouterView></RouterView>
@@ -19,16 +21,30 @@

<script setup lang="ts">
const links = [
{ text: 'Add Fund', to: '/admin/addfund' },
{ text: 'Modify Fund', to: '' },
{ text: 'Create Tag', to: '' },
{
text: 'Dashboard',
to: '/admin/dashboard',
},
{
text: 'Add Fund',
to: '/admin/addfund',
},
{
text: 'Modify Fund',
to: '/admin/modifyfund',
},
{
text: 'Add/Modify Queue',
to: '/admin/modifyqueue',
},
];

</script>

<style scoped lang="stylus">
nav
min-width 134px
min-height 100vh
height calc(100vh - 56px)

li
font-variant all-petite-caps


+ 8
- 5
src/views/FundView.vue 查看文件

@@ -1,16 +1,19 @@
<template>
<div class="container is-max-desktop pb-4">
<section class="section is-small">
<div class="title is-size-4 has-text-white-ter has-text-centered">
{{ fund.fundInfo.title }}
</div>
<div
class="is-block-mobile
is-flex-tablet-only
is-flex-desktop
is-flex-direction-row
is-justify-content-space-between">
<div class="fund-description pr-5" v-html="fixNewlines(fund.fundInfo.description)">
<div class="my-auto">
<div class="is-size-1">{{ fund.fundInfo.asset }}</div>
<div>
<a :href="fund.fundInfo.telegramLink" target="_blank" class="has-text-grey-light">
{{ fund.fundInfo.telegramLink }}
</a>
</div>
</div>
<div
class="fund-details is-flex is-flex-direction-row is-justify-content-end my-auto py-6">
@@ -375,7 +378,7 @@ const errs: SignetError[] = [
},
];

document.title = `Beignet - ${fund.value.fundInfo.title}`;
document.title = `Beignet - ${fund.value.fundInfo.asset}`;

watch(selectedDate, async (newVal) => {
offset.value = 0;


+ 24
- 0
src/views/ModifyQueueView.vue 查看文件

@@ -0,0 +1,24 @@
<template>
<div class="container is-max-desktop">
<section class="section is-small">
<div class="title is-4 has-text-white-ter has-text-centered">
Add/Modify Queue
</div>
<section class="section px-0 py-4">
<EditQueue :new-member="undefined" orientation="vertical" @created="createQueue"/>
</section>
</section>
</div>
</template>

<script setup lang="ts">

import EditQueue from '@/components/EditQueue.vue';
import { createQueue } from '@/api/composed';
//

</script>

<style scoped lang="stylus">

</style>

Loading…
取消
儲存