Capstone/ui/templates/dashboard_page.templ

563 lines
20 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package templates
import (
"fmt"
"strconv"
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models"
)
func hasVendor(name string, vendors []models.VendorAccount) bool {
for _, vendor := range vendors {
if vendor.Name == name {
return true
}
}
return false
}
func hasPco(vendors []models.VendorAccount) bool {
return hasVendor(models.PCO_VENDOR_NAME, vendors)
}
func hasYoutube(vendors []models.VendorAccount) bool {
return hasVendor(models.YOUTUBE_VENDOR_NAME, vendors)
}
templ DashboardPage(user *models.User, vendorAccounts []models.VendorAccount, actionMappings []models.ActionMapping) {
<!DOCTYPE html>
<html>
@Head("Dashboard")
<body class="text-blueGray-700 antialiased">
<div
id="add-action-modal"
aria-hidden="false"
tabindex="-1"
class="transition-all hidden"
></div>
<div id="root" class="h-screen overflow-scroll">
@DashboardNav(user)
@DashboardContent(user, vendorAccounts, actionMappings)
</div>
@DashboardFooter()
</body>
@DashboardScript()
@toggleDropdown()
</html>
}
templ DashboardNav(user *models.User) {
<nav
class="md:left-0 md:block md:fixed md:top-0 md:bottom-0 md:overflow-y-auto md:flex-row md:flex-nowrap md:overflow-hidden shadow-xl bg-white flex flex-wrap items-center justify-between relative md:w-64 z-10 py-4 px-6"
>
<div
class="md:flex-col md:items-stretch md:min-h-full md:flex-nowrap px-0 flex flex-wrap items-center justify-between w-full mx-auto"
>
<button
class="cursor-pointer text-black opacity-50 md:hidden px-3 py-1 text-xl leading-none bg-transparent rounded border border-solid border-transparent"
type="button"
onclick="toggleNavbar('example-collapse-sidebar')"
>
<i class="fas fa-bars"></i>
</button>
<a
class="md:block text-left md:pb-2 text-blueGray-600 mr-0 inline-block whitespace-nowrap text-sm uppercase font-bold p-4 px-0"
href="javascript:void(0)"
>
{ user.Email }
</a>
<div
class="md:flex md:flex-col md:items-stretch md:opacity-100 md:relative md:mt-4 md:shadow-none shadow absolute top-0 left-0 right-0 z-40 overflow-y-auto overflow-x-hidden h-auto items-center flex-1 rounded hidden"
id="example-collapse-sidebar"
>
<div
class="md:min-w-full md:hidden block pb-4 mb-4 border-b border-solid border-blueGray-200"
>
<div class="flex flex-wrap">
<div class="w-6/12">
<a
class="md:block text-left md:pb-2 text-blueGray-600 mr-0 inline-block whitespace-nowrap text-sm uppercase font-bold p-4 px-0"
href="javascript:void(0)"
>
{ user.Email }
</a>
</div>
<div class="w-6/12 flex justify-end">
<button
type="button"
class="cursor-pointer text-black opacity-50 md:hidden px-3 py-1 text-xl leading-none bg-transparent rounded border border-solid border-transparent"
onclick="toggleNavbar('example-collapse-sidebar')"
>
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<form class="mt-6 mb-4 md:hidden">
<div class="mb-3 pt-0">
<input
type="text"
placeholder="Search"
class="px-3 py-2 h-12 border border-solid border-blueGray-500 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-base leading-snug shadow-none outline-none focus:outline-none w-full font-normal"
/>
</div>
</form>
<ul class="md:flex-col md:min-w-full flex flex-col list-none">
@DashboardNavItem("fa-tv", "Dashboard", "/dashboard", true)
@DashboardNavItem("fa-chart-bar", "Events", "/dashboard/events", true)
<hr/>
@DashboardNavItem("fa-newspaper", "Home Page", "/", true)
@DashboardNavItem("fa-user-circle", "Profile (SOON)", "#", false)
</ul>
</div>
</div>
</nav>
}
templ DashboardNavItem(icon, name, link string, enabled bool) {
<li class="items-center">
<a
if enabled {
class="text-blue-500 hover:text-blue-600 text-xs uppercase py-3 font-bold block"
href={ templ.URL(link) }
} else {
class="text-blueGray-300 text-xs uppercase py-3 font-bold block"
href="#"
}
href="{ link }"
>
<i
if enabled {
class={ fmt.Sprintf("fas %s opacity-75 mr-2 text-sm", icon) }
} else {
class={ fmt.Sprintf("fas %s text-blueGray-300 mr-2 text-sm", icon) }
}
></i>{ name }
</a>
</li>
}
//Break this up
templ DashboardContentNav(user *models.User) {
<nav
class="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-center p-4"
>
<div
class="w-full mx-autp items-center flex justify-between md:flex-nowrap flex-wrap md:px-10 px-4"
>
<a
class="text-white text-sm uppercase hidden lg:inline-block font-semibold"
href="./index.html"
>Capstone</a>
<form
class="hidden flex-row flex-wrap items-center lg:ml-auto mr-3"
>
<div class="relative flex w-full flex-wrap items-stretch">
<span
class="z-10 h-full leading-snug font-normal text-center text-blueGray-300 absolute bg-transparent rounded text-base items-center justify-center w-8 pl-3 py-3"
><i class="fas fa-search"></i></span>
<input
type="text"
placeholder="Search here..."
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 relative bg-white rounded text-sm shadow outline-none focus:outline-none focus:ring w-full pl-10"
/>
</div>
</form>
<ul
class="hidden flex-col md:flex-row list-none items-center hidden md:flex"
>
<a class="hidden text-blueGray-500 block" href="#pablo" onclick="openDropdown(event,'user-dropdown')">
<div class="items-center flex">
<span
class="w-12 h-12 text-sm text-white bg-blueGray-200 inline-flex items-center justify-center rounded-full"
>
<img
alt="..."
class="w-full rounded-full align-middle border-none shadow-lg"
src="./assets/img/team-1-800x800.jpg"
/>
</span>
</div>
</a>
<div
class="hidden bg-white text-base z-50 float-left py-2 list-none text-left rounded shadow-lg mt-1"
style="min-width: 12rem;"
id="user-dropdown"
>
<a
href="#pablo"
class="text-sm py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700"
>Action</a><a
href="#pablo"
class="text-sm py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700"
>Another action</a><a
href="#pablo"
class="text-sm py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700"
>Something else here</a>
<div class="h-0 my-2 border border-solid border-blueGray-100"></div>
<a
href="#pablo"
class="text-sm py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700"
>Seprated link</a>
</div>
</ul>
</div>
</nav>
}
templ DashboardCardLoader(kind string) {
<div class="w-full lg:w-6/12 xl:w-6/12 px-4" hx-get={ fmt.Sprintf("/dashboard/components/metric_card?metric=%s", kind) } hx-trigger="load" hx-swap="outerHTML">
<div class="relative flex flex-col min-w-0 break-words bg-white rounded mb-6 xl:mb-0 shadow-lg opacity-50">
<div class="flex-auto p-4">
<div class="flex flex-wrap">
<div class="relative w-full pr-4 max-w-full flex-grow flex-1">
<h5 class="text-blueGray-400 uppercase font-bold text-xs">
---
</h5>
<span class="font-semibold text-xl text-blueGray-700">
---
</span>
</div>
<div class="relative w-auto pl-4 flex-initial">
<div class="text-white p-3 text-center inline-flex items-center justify-center w-12 h-12 shadow-lg rounded-full bg-blue-300">
<i class="far fa-chart-bar"></i>
</div>
</div>
</div>
<p class="text-sm text-blueGray-400 mt-4">
<span class="text-emerald-500 mr-2">
---
</span>
<span class="whitespace-nowrap">
---
</span>
</p>
</div>
@spinnerCentered()
</div>
</div>
}
templ DashboardCard(title, primaryVal, secondaryVal, subtitle string) {
<div class="w-full lg:w-6/12 xl:w-6/12 px-4">
<div class="relative flex flex-col min-w-0 break-words bg-white rounded mb-6 xl:mb-0 shadow-lg">
<div class="flex-auto p-4">
<div class="flex flex-wrap">
<div class="relative w-full pr-4 max-w-full flex-grow flex-1">
<h5 class="text-blueGray-400 uppercase font-bold text-xs">
{ title }
</h5>
<span class="font-semibold text-xl text-blueGray-700">
{ primaryVal }
</span>
</div>
<div class="relative w-auto pl-4 flex-initial">
<div class="text-white p-3 text-center inline-flex items-center justify-center w-12 h-12 shadow-lg rounded-full bg-blue-300">
<i class="far fa-chart-bar"></i>
</div>
</div>
</div>
<p class="text-sm text-blueGray-400 mt-4">
<span class="text-emerald-500 mr-2">
{ secondaryVal }
</span>
<span class="whitespace-nowrap">
{ subtitle }
</span>
</p>
</div>
</div>
</div>
}
templ DashboardVendorDropDown() {
<div class="flex flex-wrap float-right">
<div class="w-full sm:w-6/12 md:w-4/12 px-4">
<div class="relative inline-flex align-middle w-full">
<button class="text-white font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 bg-blueGray-500 ease-linear transition-all duration-150" type="button" onclick="openDropdown(event,'dropdown-id')">
+
</button>
<div class="hidden bg-white text-base z-50 float-left py-2 list-none text-left rounded shadow-lg mt-1" style="min-width:12rem" id="dropdown-id">
<form action="/vendor/youtube/initiate" method="POST">
<button type="submit" class="text-sm align-left py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700">
Youtube
</button>
</form>
<form action="/vendor/pco/initiate" method="POST">
<button type="submit" class="text-sm align-left py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700">
Planning Center
</button>
</form>
</div>
</div>
</div>
</div>
}
templ DashboardVendorWidget(vendors []models.VendorAccount) {
<div class="w-full xl:w-8/12 mb-12 xl:mb-0 px-4">
<div class="relative flex flex-col min-w-0 break-words bg-white w-full mb-6 shadow-lg rounded">
<div class="rounded-t mb-0 px-4 py-3 border-0">
<div class="flex flex-wrap items-center">
<div class="relative w-full px-4 max-w-full flex-grow flex-1">
<h3 class="font-semibold text-base text-blueGray-700">
Vendors
</h3>
</div>
<div class="relative w-full px-4 max-w-full flex-grow flex-1 text-right">
@DashboardVendorDropDown()
</div>
</div>
</div>
<div class="block w-full overflow-x-auto">
<!-- Projects table -->
<table class="items-center w-full bg-transparent border-collapse">
<thead>
<tr>
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
Name
</th>
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
Status
</th>
</tr>
</thead>
<tbody>
if len(vendors) == 0 {
<tr>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
No accounts are available. Click + to add one
</th>
</tr>
} else {
for _, vendor := range vendors {
<tr>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
{ vendor.Name }
</th>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
if vendor.OauthCredentials != nil && vendor.OauthCredentials.AccessToken != "" {
Active
} else {
<button>Log in</button>
}
</th>
</tr>
}
}
</tbody>
</table>
</div>
</div>
</div>
}
templ DashboardActionModalForm(vendors []models.VendorAccount) {
<div class="relative p-6 flex-auto">
<form class="space-y-4 text-gray-700" action="/dashboard/action/add" method="POST">
<div class="flex flex-wrap -mx-2 space-y-4 md:space-y-0">
<div class="w-full">
<div class="relative inline-block w-full text-gray-700">
<select class="w-full h-10 pl-3 pr-6 text-base placeholder-gray-600 border rounded-lg appearance-none focus:shadow-outline" placeholder="Choose action source" name="source">
if hasPco(vendors) {
<option value="pco.plan">Plan</option>
<option value="calendar" disabled>Calendar</option>
} else {
<option value="nil">None Available</option>
}
</select>
</div>
</div>
</div>
<div class="flex flex-wrap -mx-2 space-y-4 md:space-y-0">
<div class="w-full">
<div class="relative inline-block w-full text-gray-700">
<select class="w-full h-10 pl-3 pr-6 text-base placeholder-gray-600 border rounded-lg appearance-none focus:shadow-outline" placeholder="Choose action source" name="action">
if hasYoutube(vendors) {
<option value="youtube.livestream">Livestream</option>
<option value="video" disabled>Video</option>
} else {
<option value="nil">None Available</option>
}
</select>
</div>
</div>
</div>
<div class="flex items-center justify-end p-6 border-t border-solid border-blueGray-200 rounded-b">
<button class="text-gray-400 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150" type="button" onclick="toggleModal('add-action-modal')">
Close
</button>
<button class="bg-blue-700 text-white active:bg-blue-300 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150" type="submit">
Save Changes
</button>
</div>
</form>
</div>
}
templ DashboardActionModal(vendors []models.VendorAccount) {
<div class="transition-all ease-in-out overflow-x-hidden overflow-y-auto fixed flex inset-0 z-50 outline-none focus:outline-none justify-center items-center" id="add-action-modal">
<div class="relative w-auto my-6 mx-auto max-w-3xl">
<!--content-->
<div class="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
<!--header-->
<div class="flex items-start justify-between p-5 border-b border-solid border-blueGray-200 rounded-t">
<h3 class="text-3xl font-semibold">
Modal Title
</h3>
<button class="p-1 ml-auto bg-transparent border-0 float-right text-3xl leading-none font-semibold outline-none focus:outline-none" onclick="toggleModal('add-action-modal')">
<span class="bg-transparent text-gray-500 h-6 w-6 text-2xl block outline-none focus:outline-none">
×
</span>
</button>
</div>
<!--body-->
@DashboardActionModalForm(vendors)
<!--footer-->
</div>
</div>
</div>
<div class="opacity-25 fixed flex inset-0 z-40 bg-black" id="add-action-modal-backdrop"></div>
}
templ DashboardActionDropDown() {
<button
hx-get="/dashboard/forms/addAction"
hx-target="#add-action-modal"
hx-swap="outerHTML"
class="bg-blue-500 text-white active:bg-blue-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
>
Add Action
</button>
}
templ DashboardActionEditButton(action *models.ActionMapping) {
}
templ DashboardActionsWidget(actions []models.ActionMapping) {
<div class="w-full xl:w-8/12 mb-12 xl:mb-0 px-4">
<div class="relative flex flex-col min-w-0 break-words bg-white w-full mb-6 shadow-lg rounded">
<div class="rounded-t mb-0 px-4 py-3 border-0">
<div class="flex flex-wrap items-center">
<div class="relative w-full px-4 max-w-full flex-grow flex-1">
<h3 class="font-semibold text-base text-blueGray-700">
Vendors
</h3>
</div>
<div class="relative w-full px-4 max-w-full flex-grow flex-1 text-right">
@DashboardActionDropDown()
</div>
</div>
</div>
<div class="block w-full overflow-x-auto">
<!-- Projects table -->
<table class="items-center w-full bg-transparent border-collapse">
<thead>
<tr>
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
Id
</th>
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
Event Source
</th>
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
Event Action
</th>
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
Action
</th>
</tr>
</thead>
<tbody>
if len(actions) == 0 {
<tr>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
No actions are available. Click + to add one
</th>
</tr>
} else {
for index, action := range actions {
<tr>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
{ strconv.Itoa(index) }
</th>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
{ action.SourceEvent.Key }
</th>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
{ action.Action.VendorName }: { action.Action.Type }
</th>
<th class="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 text-left">
@DashboardActionEditButton(&action)
</th>
</tr>
}
}
</tbody>
</table>
</div>
</div>
</div>
}
templ DashboardContent(user *models.User, vendorAccounts []models.VendorAccount, actions []models.ActionMapping) {
<noscript>You need to enable JavaScript to run this app.</noscript>
<div class="relative md:ml-64 bg-blueGray-50 h-full">
@DashboardContentNav(user)
<!-- Header -->
<div class="relative bg-blue-600 md:pt-32 pb-32 pt-12">
<div class="px-4 md:px-10 mx-auto w-full">
<div>
<!-- Card stats -->
<div class="flex flex-wrap">
@DashboardCardLoader("events_received")
@DashboardCardLoader("streams_scheduled")
</div>
</div>
</div>
</div>
<div class="px-4 md:px-10 mx-auto w-full -m-24">
<div class="flex flex-wrap">
@DashboardVendorWidget(vendorAccounts)
</div>
<div class="flex flex-wrap">
@DashboardActionsWidget(actions)
</div>
</div>
</div>
}
templ DashboardScript() {
<script type="text/javascript">
function toggleModal(modalID) {
document.getElementById(modalID).classList.toggle("hidden");
document.getElementById(modalID + "-backdrop").classList.toggle("hidden");
document.getElementById(modalID).classList.toggle("flex");
document.getElementById(modalID + "-backdrop").classList.toggle("flex");
}
function toggleNavbar(collapseID) {
document.getElementById(collapseID).classList.toggle("hidden");
document.getElementById(collapseID).classList.toggle("bg-white");
document.getElementById(collapseID).classList.toggle("m-2");
document.getElementById(collapseID).classList.toggle("py-3");
document.getElementById(collapseID).classList.toggle("px-6");
}
/* Function for dropdowns */
function openDropdown(event, dropdownID) {
let element = event.target;
while (element.nodeName !== "A") {
element = element.parentNode;
}
var popper = Popper.createPopper(element, document.getElementById(dropdownID), {
placement: "bottom-end"
});
document.getElementById(dropdownID).classList.toggle("hidden");
document.getElementById(dropdownID).classList.toggle("relative");
}
</script>
}