mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 22:44:29 +01:00
more integration
This commit is contained in:
@@ -124,7 +124,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Build\" />
|
<Folder Include="Build\" />
|
||||||
<Folder Include="Views\AppsPublic\Crowdfund\Templates" />
|
|
||||||
<Folder Include="wwwroot\vendor\clipboard.js\" />
|
<Folder Include="wwwroot\vendor\clipboard.js\" />
|
||||||
<Folder Include="wwwroot\vendor\highlightjs\" />
|
<Folder Include="wwwroot\vendor\highlightjs\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
public partial class AppsController
|
public partial class AppsController
|
||||||
{
|
{
|
||||||
|
public class CrowdfundAppUpdated
|
||||||
|
{
|
||||||
|
public string AppId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class CrowdfundSettings
|
public class CrowdfundSettings
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
@@ -51,7 +56,7 @@ namespace BTCPayServer.Controllers
|
|||||||
TargetAmount = settings.TargetAmount,
|
TargetAmount = settings.TargetAmount,
|
||||||
CustomCSSLink = settings.CustomCSSLink,
|
CustomCSSLink = settings.CustomCSSLink,
|
||||||
NotificationUrl = settings.NotificationUrl,
|
NotificationUrl = settings.NotificationUrl,
|
||||||
Tagline = settings.Tagline
|
Tagline = settings.Tagline,
|
||||||
};
|
};
|
||||||
return View(vm);
|
return View(vm);
|
||||||
}
|
}
|
||||||
@@ -70,10 +75,10 @@ namespace BTCPayServer.Controllers
|
|||||||
Title = vm.Title,
|
Title = vm.Title,
|
||||||
Enabled = vm.Enabled,
|
Enabled = vm.Enabled,
|
||||||
EnforceTargetAmount = vm.EnforceTargetAmount,
|
EnforceTargetAmount = vm.EnforceTargetAmount,
|
||||||
StartDate = vm.StartDate?.ToUniversalTime(),
|
StartDate = vm.StartDate,
|
||||||
TargetCurrency = vm.TargetCurrency,
|
TargetCurrency = vm.TargetCurrency,
|
||||||
Description = vm.Description,
|
Description = vm.Description,
|
||||||
EndDate = vm.EndDate?.ToUniversalTime(),
|
EndDate = vm.EndDate,
|
||||||
TargetAmount = vm.TargetAmount,
|
TargetAmount = vm.TargetAmount,
|
||||||
CustomCSSLink = vm.CustomCSSLink,
|
CustomCSSLink = vm.CustomCSSLink,
|
||||||
MainImageUrl = vm.MainImageUrl,
|
MainImageUrl = vm.MainImageUrl,
|
||||||
@@ -82,6 +87,10 @@ namespace BTCPayServer.Controllers
|
|||||||
Tagline = vm.Tagline
|
Tagline = vm.Tagline
|
||||||
});
|
});
|
||||||
await UpdateAppSettings(app);
|
await UpdateAppSettings(app);
|
||||||
|
_EventAggregator.Publish(new CrowdfundAppUpdated()
|
||||||
|
{
|
||||||
|
AppId = appId
|
||||||
|
});
|
||||||
StatusMessage = "App updated";
|
StatusMessage = "App updated";
|
||||||
return RedirectToAction(nameof(ListApps));
|
return RedirectToAction(nameof(ListApps));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,17 +24,20 @@ namespace BTCPayServer.Controllers
|
|||||||
public AppsController(
|
public AppsController(
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
ApplicationDbContextFactory contextFactory,
|
ApplicationDbContextFactory contextFactory,
|
||||||
|
EventAggregator eventAggregator,
|
||||||
BTCPayNetworkProvider networkProvider,
|
BTCPayNetworkProvider networkProvider,
|
||||||
AppsHelper appsHelper)
|
AppsHelper appsHelper)
|
||||||
{
|
{
|
||||||
_UserManager = userManager;
|
_UserManager = userManager;
|
||||||
_ContextFactory = contextFactory;
|
_ContextFactory = contextFactory;
|
||||||
|
_EventAggregator = eventAggregator;
|
||||||
_NetworkProvider = networkProvider;
|
_NetworkProvider = networkProvider;
|
||||||
_AppsHelper = appsHelper;
|
_AppsHelper = appsHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserManager<ApplicationUser> _UserManager;
|
private UserManager<ApplicationUser> _UserManager;
|
||||||
private ApplicationDbContextFactory _ContextFactory;
|
private ApplicationDbContextFactory _ContextFactory;
|
||||||
|
private readonly EventAggregator _EventAggregator;
|
||||||
private BTCPayNetworkProvider _NetworkProvider;
|
private BTCPayNetworkProvider _NetworkProvider;
|
||||||
private AppsHelper _AppsHelper;
|
private AppsHelper _AppsHelper;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
using BTCPayServer.Hubs;
|
using BTCPayServer.Hubs;
|
||||||
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.AppViewModels;
|
using BTCPayServer.Models.AppViewModels;
|
||||||
using BTCPayServer.Rating;
|
using BTCPayServer.Rating;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
@@ -16,6 +17,7 @@ using BTCPayServer.Services.Invoices;
|
|||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NBitpayClient;
|
using NBitpayClient;
|
||||||
@@ -28,16 +30,18 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
public AppsPublicController(AppsHelper appsHelper,
|
public AppsPublicController(AppsHelper appsHelper,
|
||||||
InvoiceController invoiceController,
|
InvoiceController invoiceController,
|
||||||
CrowdfundHubStreamer crowdfundHubStreamer)
|
CrowdfundHubStreamer crowdfundHubStreamer, UserManager<ApplicationUser> userManager)
|
||||||
{
|
{
|
||||||
_AppsHelper = appsHelper;
|
_AppsHelper = appsHelper;
|
||||||
_InvoiceController = invoiceController;
|
_InvoiceController = invoiceController;
|
||||||
_CrowdfundHubStreamer = crowdfundHubStreamer;
|
_CrowdfundHubStreamer = crowdfundHubStreamer;
|
||||||
|
_UserManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppsHelper _AppsHelper;
|
private AppsHelper _AppsHelper;
|
||||||
private InvoiceController _InvoiceController;
|
private InvoiceController _InvoiceController;
|
||||||
private readonly CrowdfundHubStreamer _CrowdfundHubStreamer;
|
private readonly CrowdfundHubStreamer _CrowdfundHubStreamer;
|
||||||
|
private readonly UserManager<ApplicationUser> _UserManager;
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/apps/{appId}/pos")]
|
[Route("/apps/{appId}/pos")]
|
||||||
@@ -87,7 +91,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
{
|
{
|
||||||
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true);
|
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true);
|
||||||
if (app == null)
|
if (app == null ||
|
||||||
|
(!app.GetSettings<CrowdfundSettings>().Enabled &&
|
||||||
|
_AppsHelper.GetAppDataIfOwner(GetUserId(), appId, AppType.Crowdfund) == null))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return View(await _CrowdfundHubStreamer.GetCrowdfundInfo(appId));
|
return View(await _CrowdfundHubStreamer.GetCrowdfundInfo(appId));
|
||||||
@@ -101,7 +107,9 @@ namespace BTCPayServer.Controllers
|
|||||||
public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request)
|
public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request)
|
||||||
{
|
{
|
||||||
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true);
|
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true);
|
||||||
if (app == null)
|
if (app == null ||
|
||||||
|
(!app.GetSettings<CrowdfundSettings>().Enabled &&
|
||||||
|
_AppsHelper.GetAppDataIfOwner(GetUserId(), appId, AppType.Crowdfund) == null))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
var settings = app.GetSettings<CrowdfundSettings>();
|
var settings = app.GetSettings<CrowdfundSettings>();
|
||||||
var store = await _AppsHelper.GetStore(app);
|
var store = await _AppsHelper.GetStore(app);
|
||||||
@@ -191,6 +199,12 @@ namespace BTCPayServer.Controllers
|
|||||||
}, store, HttpContext.Request.GetAbsoluteRoot());
|
}, store, HttpContext.Request.GetAbsoluteRoot());
|
||||||
return RedirectToAction(nameof(InvoiceController.Checkout), "Invoice", new { invoiceId = invoice.Data.Id });
|
return RedirectToAction(nameof(InvoiceController.Checkout), "Invoice", new { invoiceId = invoice.Data.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetUserId()
|
||||||
|
{
|
||||||
|
return _UserManager.GetUserId(User);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AppsHelper
|
public class AppsHelper
|
||||||
@@ -310,5 +324,6 @@ namespace BTCPayServer.Controllers
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ namespace BTCPayServer.Hubs
|
|||||||
var token = new CancellationTokenSource();
|
var token = new CancellationTokenSource();
|
||||||
_CacheTokens.Add(key, token);
|
_CacheTokens.Add(key, token);
|
||||||
entry.AddExpirationToken(new CancellationChangeToken(token.Token));
|
entry.AddExpirationToken(new CancellationChangeToken(token.Token));
|
||||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(20);
|
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true);
|
var app = await _AppsHelper.GetApp(appId, AppType.Crowdfund, true);
|
||||||
var result = await GetInfo(app, _InvoiceRepository, _RateFetcher,
|
var result = await GetInfo(app, _InvoiceRepository, _RateFetcher,
|
||||||
@@ -110,6 +110,10 @@ namespace BTCPayServer.Hubs
|
|||||||
{
|
{
|
||||||
|
|
||||||
_EventAggregator.Subscribe<InvoiceEvent>(Subscription);
|
_EventAggregator.Subscribe<InvoiceEvent>(Subscription);
|
||||||
|
_EventAggregator.Subscribe<AppsController.CrowdfundAppUpdated>(updated =>
|
||||||
|
{
|
||||||
|
InvalidateCacheForApp(updated.AppId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCacheKey(string appId)
|
private string GetCacheKey(string appId)
|
||||||
@@ -127,16 +131,21 @@ namespace BTCPayServer.Hubs
|
|||||||
switch (invoiceEvent.Name)
|
switch (invoiceEvent.Name)
|
||||||
{
|
{
|
||||||
case InvoiceEvent.ReceivedPayment:
|
case InvoiceEvent.ReceivedPayment:
|
||||||
_HubContext.Clients.Group(appId).SendCoreAsync("PaymentReceived", new object[]{ invoiceEvent.Invoice.AmountPaid } );
|
_HubContext.Clients.Group(appId).SendCoreAsync("PaymentReceived", new object[]{ invoiceEvent.Invoice.CryptoInfo.First().Paid } );
|
||||||
break;
|
break;
|
||||||
case InvoiceEvent.Completed:
|
case InvoiceEvent.Completed:
|
||||||
|
InvalidateCacheForApp(appId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InvalidateCacheForApp(string appId)
|
||||||
|
{
|
||||||
if (_CacheTokens.ContainsKey(appId))
|
if (_CacheTokens.ContainsKey(appId))
|
||||||
{
|
{
|
||||||
_CacheTokens[appId].Cancel();
|
_CacheTokens[appId].Cancel();
|
||||||
}
|
}
|
||||||
_HubContext.Clients.Group(appId).SendCoreAsync("InfoUpdated", new object[]{} );
|
_HubContext.Clients.Group(appId).SendCoreAsync("InfoUpdated", new object[]{} );
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<decimal> GetCurrentContributionAmount(InvoiceEntity[] invoices, string primaryCurrency,
|
private static async Task<decimal> GetCurrentContributionAmount(InvoiceEntity[] invoices, string primaryCurrency,
|
||||||
@@ -171,18 +180,24 @@ namespace BTCPayServer.Hubs
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ViewCrowdfundViewModel> GetInfo(AppData appData, InvoiceRepository invoiceRepository,
|
private static async Task<ViewCrowdfundViewModel> GetInfo(AppData appData, InvoiceRepository invoiceRepository,
|
||||||
RateFetcher rateFetcher, BTCPayNetworkProvider btcPayNetworkProvider, string statusMessage= null)
|
RateFetcher rateFetcher, BTCPayNetworkProvider btcPayNetworkProvider, string statusMessage= null)
|
||||||
{
|
{
|
||||||
var settings = appData.GetSettings<AppsController.CrowdfundSettings>();
|
var settings = appData.GetSettings<AppsController.CrowdfundSettings>();
|
||||||
var invoices = await GetPaidInvoicesForApp(appData, invoiceRepository);
|
var invoices = await GetInvoicesForApp(appData, invoiceRepository);
|
||||||
|
|
||||||
|
|
||||||
var rateRules = appData.StoreData.GetStoreBlob().GetRateRules(btcPayNetworkProvider);
|
var rateRules = appData.StoreData.GetStoreBlob().GetRateRules(btcPayNetworkProvider);
|
||||||
var currentAmount = await GetCurrentContributionAmount(
|
var currentAmount = await GetCurrentContributionAmount(
|
||||||
invoices,
|
invoices.Where(entity => entity.Status == InvoiceStatus.Complete).ToArray(),
|
||||||
settings.TargetCurrency, rateFetcher, rateRules);
|
settings.TargetCurrency, rateFetcher, rateRules);
|
||||||
var paidInvoices = invoices.Length;
|
var currentPendingAmount = await GetCurrentContributionAmount(
|
||||||
var active = (settings.StartDate == null || DateTime.UtcNow >= settings.StartDate) &&
|
invoices.Where(entity => entity.Status != InvoiceStatus.Complete).ToArray(),
|
||||||
(settings.EndDate == null || DateTime.UtcNow <= settings.EndDate) &&
|
settings.TargetCurrency, rateFetcher, rateRules);
|
||||||
|
|
||||||
|
|
||||||
|
var active = (settings.StartDate == null || DateTime.Now >= settings.StartDate) &&
|
||||||
|
(settings.EndDate == null || DateTime.Now <= settings.EndDate) &&
|
||||||
(!settings.EnforceTargetAmount || settings.TargetAmount > currentAmount);
|
(!settings.EnforceTargetAmount || settings.TargetAmount > currentAmount);
|
||||||
|
|
||||||
return new ViewCrowdfundViewModel()
|
return new ViewCrowdfundViewModel()
|
||||||
@@ -203,23 +218,29 @@ namespace BTCPayServer.Hubs
|
|||||||
StatusMessage = statusMessage,
|
StatusMessage = statusMessage,
|
||||||
Info = new ViewCrowdfundViewModel.CrowdfundInfo()
|
Info = new ViewCrowdfundViewModel.CrowdfundInfo()
|
||||||
{
|
{
|
||||||
TotalContributors = paidInvoices,
|
TotalContributors = invoices.Length,
|
||||||
|
CurrentPendingAmount = currentPendingAmount,
|
||||||
CurrentAmount = currentAmount,
|
CurrentAmount = currentAmount,
|
||||||
Active = active,
|
Active = active,
|
||||||
DaysLeft = settings.EndDate.HasValue? (settings.EndDate - DateTime.UtcNow).Value.Days: (int?) null,
|
DaysLeft = settings.EndDate.HasValue? (settings.EndDate - DateTime.UtcNow).Value.Days: (int?) null,
|
||||||
DaysLeftToStart = settings.StartDate.HasValue? (settings.StartDate - DateTime.UtcNow).Value.Days: (int?) null,
|
DaysLeftToStart = settings.StartDate.HasValue? (settings.StartDate - DateTime.UtcNow).Value.Days: (int?) null,
|
||||||
ShowProgress =active && settings.TargetAmount.HasValue,
|
ShowProgress = settings.TargetAmount.HasValue,
|
||||||
ProgressPercentage = currentAmount/ settings.TargetAmount * 100
|
ProgressPercentage = (currentAmount/ settings.TargetAmount) * 100,
|
||||||
|
PendingProgressPercentage = ( currentPendingAmount/ settings.TargetAmount) * 100
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<InvoiceEntity[]> GetPaidInvoicesForApp(AppData appData, InvoiceRepository invoiceRepository)
|
private static async Task<InvoiceEntity[]> GetInvoicesForApp(AppData appData, InvoiceRepository invoiceRepository)
|
||||||
{
|
{
|
||||||
return await invoiceRepository.GetInvoices(new InvoiceQuery()
|
return await invoiceRepository.GetInvoices(new InvoiceQuery()
|
||||||
{
|
{
|
||||||
OrderId = appData.Id,
|
OrderId = $"{CrowdfundInvoiceOrderIdPrefix}{appData.Id}",
|
||||||
Status = new string[]{ InvoiceState.ToString(InvoiceStatus.Complete)}
|
Status = new string[]{
|
||||||
|
InvoiceState.ToString(InvoiceStatus.New),
|
||||||
|
InvoiceState.ToString(InvoiceStatus.Paid),
|
||||||
|
InvoiceState.ToString(InvoiceStatus.Confirmed),
|
||||||
|
InvoiceState.ToString(InvoiceStatus.Complete)}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace BTCPayServer.Models.AppViewModels
|
|||||||
[MaxLength(30)]
|
[MaxLength(30)]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(50)]
|
||||||
|
public string Tagline { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string MainImageUrl { get; set; }
|
public string MainImageUrl { get; set; }
|
||||||
@@ -16,7 +19,7 @@ namespace BTCPayServer.Models.AppViewModels
|
|||||||
public string NotificationUrl { get; set; }
|
public string NotificationUrl { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; } = false;
|
||||||
|
|
||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
@@ -37,7 +40,6 @@ namespace BTCPayServer.Models.AppViewModels
|
|||||||
[Display(Name = "Custom bootstrap CSS file")]
|
[Display(Name = "Custom bootstrap CSS file")]
|
||||||
public string CustomCSSLink { get; set; }
|
public string CustomCSSLink { get; set; }
|
||||||
|
|
||||||
public string Tagline { get; set; }
|
|
||||||
public string EmbeddedCSS { get; set; }
|
public string EmbeddedCSS { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ namespace BTCPayServer.Models.AppViewModels
|
|||||||
public decimal? ProgressPercentage { get; set; }
|
public decimal? ProgressPercentage { get; set; }
|
||||||
public int? DaysLeft{ get; set; }
|
public int? DaysLeft{ get; set; }
|
||||||
public int? DaysLeftToStart{ get; set; }
|
public int? DaysLeftToStart{ get; set; }
|
||||||
|
public decimal CurrentPendingAmount { get; set; }
|
||||||
|
public decimal? PendingProgressPercentage { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,97 +2,135 @@
|
|||||||
<div class="row h-100 w-100 py-sm-0 py-md-4 mx-0">
|
<div class="row h-100 w-100 py-sm-0 py-md-4 mx-0">
|
||||||
<div class="card w-100 p-0 mx-0">
|
<div class="card w-100 p-0 mx-0">
|
||||||
<img class="card-img-top" :src="srvModel.mainImageUrl" v-if="srvModel.mainImageUrl">
|
<img class="card-img-top" :src="srvModel.mainImageUrl" v-if="srvModel.mainImageUrl">
|
||||||
<div class="progress rounded-0 striped" style="min-height: 30px" v-if="srvModel.info.showProgres">
|
<div class="progress rounded-0" style="min-height: 30px" v-if="srvModel.info.showProgress">
|
||||||
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" :aria-valuenow="srvModel.info.progressPercentage" aria-valuemin="0" aria-valuemax="100">
|
<div class="progress-bar p" role="progressbar" :aria-valuenow="srvModel.info.progressPercentage" aria-valuemin="0" aria-valuemax="100">
|
||||||
<template v-if="srvModel.info.progressPercentage > 0">
|
<template v-if="srvModel.info.progressPercentage > 0">
|
||||||
{{srvModel.info.progressPercentage}} %
|
{{srvModel.info.progressPercentage}} % Funded
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar bg-warning" role="progressbar" :aria-valuenow="srvModel.info.progressPercentage" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<template v-if="srvModel.info.progressPercentage > 0">
|
||||||
|
{{srvModel.info.pendingProgressPercentage}} % Pending
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title row">
|
||||||
|
<div class="col-md-6 col-sm-12">
|
||||||
|
|
||||||
|
<span class="h1" >
|
||||||
|
{{srvModel.title}}
|
||||||
|
<span class="h6 text-muted" v-if="!started && srvModel.startDate">
|
||||||
|
Starts {{startDateRelativeTime}}
|
||||||
|
</span>
|
||||||
|
<span class="h6 " v-else-if="started && !ended && srvModel.endDate">
|
||||||
|
Ends {{endDateRelativeTime}}
|
||||||
|
</span>
|
||||||
|
<span class="h6 text-muted" v-else-if="started && !ended && srvModel.endDate">
|
||||||
|
Currently Active!
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<h2 class="text-muted" v-if="srvModel.tagline">{{srvModel.tagline}}</h2>
|
||||||
|
<button v-if="srvModel.info.active" class="btn btn-lg btn-primary w-100" v-on:click="contributeModalOpen = true">Contribute</button>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<ul class="list-group list-group-flush col-md-6 col-sm-12">
|
||||||
|
<li class="list-group-item border-0">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div>
|
||||||
|
<span class="h5">{{srvModel.info.currentAmount + srvModel.info.currentPendingAmount }} {{targetCurrency}} </span>
|
||||||
|
<span>raised by {{srvModel.info.totalContributors}} contributors </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="progress w-100" v-if="srvModel.info.showProgress">
|
||||||
|
<div class="progress-bar" role="progressbar"
|
||||||
|
:aria-valuenow="srvModel.info.progressPercentage"
|
||||||
|
v-bind:style="{ width: srvModel.info.progressPercentage + '%' }"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100">
|
||||||
|
<template v-if="srvModel.info.progressPercentage > 0">
|
||||||
|
{{srvModel.info.progressPercentage}}% Funded
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar bg-warning" role="progressbar"
|
||||||
|
:aria-valuenow="srvModel.info.pendingProgressPercentage"
|
||||||
|
v-bind:style="{ width: srvModel.info.pendingProgressPercentage + '%' }"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100">
|
||||||
|
<template v-if="srvModel.info.pendingProgressPercentage > 0">
|
||||||
|
{{srvModel.info.pendingProgressPercentage}}% Pending
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
|
||||||
<div class="card-title row">
|
|
||||||
<div class="col-md-9 col-sm-12">
|
|
||||||
|
|
||||||
<h1 >
|
|
||||||
{{srvModel.title}}
|
|
||||||
<h2 class="text-muted" v-if="srvModel.tagline">{{srvModel.tagline}}</h2>
|
|
||||||
<small v-if="srvModel.info.daysLeftToStart && srvModel.info.daysLeftToStart > 0">
|
|
||||||
{{ srvModel.info.daysLeftToStart }} days left to start
|
|
||||||
</small>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<ul class="list-group list-group-flush col-md-3 col-sm-12">
|
|
||||||
<li class="list-group-item" v-if="startDate">
|
|
||||||
<template>{{started}} {{ended}}</template>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item" v-if="startDate">
|
|
||||||
<template>Starts {{startDate}}</template>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<template v-if="endDate">Ends {{endDate}}</template>
|
|
||||||
<template v-else>No specific end date</template>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<template v-if="srvModel.targetAmount">{{srvModel.targetAmount}} {{srvModel.targetCurrency}} Goal</template>
|
|
||||||
<template v-else>No specific target goal</template>
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<template v-if="srvModel.enforceTargetAmount">Hardcap Goal</template>
|
<span v-if="srvModel.targetAmount" class="h5">{{srvModel.targetAmount}} {{targetCurrency}}</span>
|
||||||
<template v-else>Softcap Goal</template>
|
|
||||||
|
<span v-if="srvModel.enforceTargetAmount">Hardcap Goal <small>- No contributions allowed after the goal has been reached</small></span>
|
||||||
|
<span v-else>Softcap Goal <small>- Contributions allowed after goal is reached</small></span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<template v-if="startDate">
|
||||||
|
<template v-if="started">
|
||||||
|
Started {{startDate}}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="!started">
|
||||||
|
Starts {{startDate}}
|
||||||
|
</template>
|
||||||
|
&
|
||||||
|
</template>
|
||||||
|
<template class="list-group-item" v-if="endDate">
|
||||||
|
<template v-if="!ended">
|
||||||
|
Ends {{endDate}}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="ended">
|
||||||
|
Ended {{endDate}}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template class="list-group-item" v-else-if="!endDate">
|
||||||
|
No specific end date
|
||||||
|
</template>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-deck mb-4" v-if="srvModel.info.active">
|
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title text-center">{{srvModel.info.totalContributors}}</h5>
|
|
||||||
<h6 class="card-text text-center"> Contributors</h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title text-center">{{srvModel.info.currentAmount}} {{srvModel.info.targetCurrency}}</h5>
|
|
||||||
<h6 class="card-text text-center"> Raised</h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card shadow" v-if="srvModel.info.daysLeft && srvModel.info.daysLeft >0">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title text-center">Ends {{endDateRelativeTime}}</h5>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card-text" v-html="srvModel.description"></div>
|
|
||||||
<template v-if="srvModel.info.active"></template>
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<h3>Contribute</h3>
|
<div class="row">
|
||||||
|
<div class="col-md-8 col-sm-12">
|
||||||
<form v-on:submit="onContributeFormSubmit">
|
<div class="card-text" v-html="srvModel.description"></div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label ></label>
|
|
||||||
<input type="email" class="form-control" v-model="contributionForm.email"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="col-md-4 col-sm-12">
|
||||||
<label ></label>
|
<contribute :target-currency="srvModel.targetCurrency" :active="srvModel.info.active"></contribute>
|
||||||
<div class="input-group mb-3">
|
|
||||||
<input type="number" step="any" class="form-control" v-model="contributionForm.amount"/>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text">{{srvModel.targetCurrency}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Contribute</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<b-modal title="Contribute" v-model="contributeModalOpen" v-on:ok="submitModalContribute" :hide-header-close="true">
|
||||||
|
|
||||||
|
<contribute :target-currency="srvModel.targetCurrency" :active="srvModel.info.active" ref="modalContribute" :in-modal="true"></contribute>
|
||||||
|
<template slot="modal-ok">
|
||||||
|
Submit
|
||||||
|
</template>
|
||||||
|
</b-modal>
|
||||||
|
<b-modal title="Thank You!" v-model="thankYouModalOpen" :ok-only="true">
|
||||||
|
Thank you for your contribution.
|
||||||
|
</b-modal>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -67,6 +67,7 @@
|
|||||||
"outputFileName": "wwwroot/bundles/crowdfund-bundle.min.js",
|
"outputFileName": "wwwroot/bundles/crowdfund-bundle.min.js",
|
||||||
"inputFiles": [
|
"inputFiles": [
|
||||||
"wwwroot/vendor/vuejs/vue.min.js",
|
"wwwroot/vendor/vuejs/vue.min.js",
|
||||||
|
"wwwroot/vendor/vue-toasted/vue-toasted.min.js",
|
||||||
"wwwroot/vendor/babel-polyfill/polyfill.min.js",
|
"wwwroot/vendor/babel-polyfill/polyfill.min.js",
|
||||||
"wwwroot/vendor/bootstrap-vue/bootstrap-vue.js",
|
"wwwroot/vendor/bootstrap-vue/bootstrap-vue.js",
|
||||||
"wwwroot/vendor/signalr/signalr.js",
|
"wwwroot/vendor/signalr/signalr.js",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
var app = null;
|
var app = null;
|
||||||
var eventAggregator = new Vue();
|
var eventAggregator = new Vue();
|
||||||
window.onload = function (ev) {
|
window.onload = function (ev) {
|
||||||
|
Vue.use(Toasted);
|
||||||
app = new Vue({
|
app = new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
data: function(){
|
data: function(){
|
||||||
@@ -13,10 +14,15 @@ window.onload = function (ev) {
|
|||||||
endDateRelativeTime: "",
|
endDateRelativeTime: "",
|
||||||
started: false,
|
started: false,
|
||||||
ended: false,
|
ended: false,
|
||||||
contributionForm: { email: "", amount: 0}
|
contributeModalOpen: false,
|
||||||
|
thankYouModalOpen: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
targetCurrency: function(){
|
||||||
|
return this.srvModel.targetCurrency.toUpperCase();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
|
||||||
methods: {
|
methods: {
|
||||||
updateComputed: function () {
|
updateComputed: function () {
|
||||||
if (this.srvModel.endDate) {
|
if (this.srvModel.endDate) {
|
||||||
@@ -25,7 +31,7 @@ window.onload = function (ev) {
|
|||||||
this.endDateRelativeTime = endDateM.fromNow();
|
this.endDateRelativeTime = endDateM.fromNow();
|
||||||
this.ended = endDateM.isBefore(moment());
|
this.ended = endDateM.isBefore(moment());
|
||||||
}else{
|
}else{
|
||||||
this.ended = true;
|
this.ended = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.srvModel.startDate) {
|
if (this.srvModel.startDate) {
|
||||||
@@ -38,22 +44,27 @@ window.onload = function (ev) {
|
|||||||
}
|
}
|
||||||
setTimeout(this.updateComputed, 1000);
|
setTimeout(this.updateComputed, 1000);
|
||||||
},
|
},
|
||||||
onContributeFormSubmit: function(e){
|
submitModalContribute: function(e){
|
||||||
if(e){
|
debugger;
|
||||||
e.preventDefault();
|
this.$refs.modalContribute.onContributeFormSubmit(e);
|
||||||
}
|
|
||||||
eventAggregator.$emit("contribute", this.contributionForm);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
hubListener.connect();
|
hubListener.connect();
|
||||||
|
var self = this;
|
||||||
eventAggregator.$on("invoice-created", function (invoiceId) {
|
eventAggregator.$on("invoice-created", function (invoiceId) {
|
||||||
btcpay.setApiUrlPrefix(window.location.origin);
|
btcpay.setApiUrlPrefix(window.location.origin);
|
||||||
btcpay.showInvoice(invoiceId);
|
btcpay.showInvoice(invoiceId);
|
||||||
btcpay.showFrame();
|
btcpay.showFrame();
|
||||||
|
|
||||||
|
self.contributeModalOpen = false;
|
||||||
});
|
});
|
||||||
|
btcpay.onModalWillLeave = function(){
|
||||||
|
self.thankYouModalOpen = true;
|
||||||
|
};
|
||||||
eventAggregator.$on("payment-received", function (amount) {
|
eventAggregator.$on("payment-received", function (amount) {
|
||||||
console.warn("AAAAAA", amount);
|
console.warn("AAAAAA", amount);
|
||||||
|
Vue.toasted.show('New payment of ' + amount+ " BTC registered");
|
||||||
});
|
});
|
||||||
eventAggregator.$on("info-updated", function (model) {
|
eventAggregator.$on("info-updated", function (model) {
|
||||||
this.srvModel = model;
|
this.srvModel = model;
|
||||||
|
|||||||
@@ -1,7 +1,43 @@
|
|||||||
Vue.component('contribute', {
|
Vue.component('contribute', {
|
||||||
|
props: ["targetCurrency", "active", "inModal"],
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
email: "",
|
||||||
|
amount: 0,
|
||||||
|
choiceKey: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: ''
|
methods: {
|
||||||
|
onContributeFormSubmit: function (e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
if(!this.active){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventAggregator.$emit("contribute", {email: this.email, amount: this.amount, choiceKey: this.choiceKey});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
template: "<div>" +
|
||||||
|
"<h3 v-if='!inModal'>Contribute</h3>" +
|
||||||
|
"" +
|
||||||
|
" <form v-on:submit=\"onContributeFormSubmit\">" +
|
||||||
|
"" +
|
||||||
|
" <div class=\"form-group\">" +
|
||||||
|
" <label ></label>" +
|
||||||
|
" <input type=\"email\" class=\"form-control\" v-model=\"email\" placeholder='Email'/>" +
|
||||||
|
" </div>" +
|
||||||
|
" <div class=\"form-group\">" +
|
||||||
|
" <label ></label>" +
|
||||||
|
" <div class=\"input-group mb-3\">" +
|
||||||
|
" <input type=\"number\" step=\"any\" class=\"form-control\" v-model=\"amount\" placeholder='Contribution Amount'/>" +
|
||||||
|
" <div class=\"input-group-append\">" +
|
||||||
|
" <span class=\"input-group-text\">{{targetCurrency}}</span>" +
|
||||||
|
" </div>" +
|
||||||
|
" </div>" +
|
||||||
|
" </div>" +
|
||||||
|
" <button type=\"submit\" class=\"btn btn-primary\" :disabled='!active' v-if='!inModal'>Contribute</button>" +
|
||||||
|
" </form>" +
|
||||||
|
"</div>"
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user