Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/APIFunctions/PermissionRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ApiResponse } from './ApiResponses';
import { BASE_API_URL } from '../Enums';

export async function getPermissionRequest(type, token) {
const status = new ApiResponse();
const url = new URL('/api/PermissionRequest/get', BASE_API_URL);
url.searchParams.append('type', type);

try {
const res = await fetch(url.toString(), {
headers: {
Authorization: `Bearer ${token}`,
},
});

if (res.ok) {
const data = await res.json();
status.responseData = data;
} else if (res.status === 404) {
status.responseData = null;
} else {
status.error = true;
}
} catch (err) {
status.responseData = err;
status.error = true;
}

return status;
}

export async function createPermissionRequest(type, token) {
const status = new ApiResponse();
const url = new URL('/api/PermissionRequest/create', BASE_API_URL);

try {
const res = await fetch(url.toString(), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ type }),
});

if (res.ok) {
const data = await res.json();
status.responseData = data;
} else {
status.error = true;
}
} catch (err) {
status.responseData = err;
status.error = true;
}

return status;
}

197 changes: 138 additions & 59 deletions src/Pages/LedSign/LedSign.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useState, useEffect } from 'react';
import { healthCheck, updateSignText } from '../../APIFunctions/LedSign';
import { getPermissionRequest, createPermissionRequest } from '../../APIFunctions/PermissionRequest';
import { useSCE } from '../../Components/context/SceContext';
import { membershipState } from '../../Enums';

import './ledsign.css';

Expand All @@ -20,6 +22,9 @@ function LedSign() {
const [awaitingSignResponse, setAwaitingSignResponse] = useState(false);
const [requestSuccessful, setRequestSuccessful] = useState();
const [stopRequestSuccesful, setStopRequestSuccesful] = useState();
const [permissionRequest, setPermissionRequest] = useState(null);
const [checkingPermission, setCheckingPermission] = useState(false);
const [requestingPermission, setRequestingPermission] = useState(false);
const inputArray = [
{
title: 'Sign Text:',
Expand Down Expand Up @@ -211,11 +216,24 @@ function LedSign() {
}
setLoading(false);
}

async function checkPermission() {
if (user.accessLevel < membershipState.OFFICER) {
setCheckingPermission(true);
const result = await getPermissionRequest('LED_SIGN', user.token);
if (!result.error && result.responseData) {
setPermissionRequest(result.responseData);
}
setCheckingPermission(false);
}
}

checkSignHealth();
checkPermission();
// eslint-disable-next-line
}, [])

if (loading) {
if (loading || checkingPermission) {
return (
<svg className="animate-spin h-5 w-5 mr-3 ..." viewBox="0 0 24 24">
</svg>
Expand All @@ -231,6 +249,60 @@ function LedSign() {
);
}

async function handleRequestAccess() {
setRequestingPermission(true);
const result = await createPermissionRequest('LED_SIGN', user.token);
if (!result.error) {
setPermissionRequest(result.responseData);
}
setRequestingPermission(false);
}

function renderPermissionRequestUI() {
if (user.accessLevel >= membershipState.OFFICER) {
return null;
}

if (checkingPermission) {
return (
<div className="w-2/3 lg:w-1/2 text-center py-4">
<p>Checking access...</p>
</div>
);
}

if (permissionRequest) {
return (
<div className="w-2/3 lg:w-1/2 text-center py-4 space-y-2">
<p className="text-gray-700 dark:text-gray-300">
You requested access to the sign on {getFormattedTime(permissionRequest.createdAt)}.
</p>
<p className="text-sm text-gray-600 dark:text-gray-400 italic">
Drop a message in Discord to speed up the process!
</p>
</div>
);
}

return (
<div className="w-2/3 lg:w-1/2 text-center py-4 space-y-2">
<p className="text-gray-700 dark:text-gray-300">
You need permission to access the LED sign.
</p>
<button
className="btn bg-blue-500 hover:bg-blue-400 text-white"
onClick={handleRequestAccess}
disabled={requestingPermission}
>
{requestingPermission ? 'Requesting...' : 'Request Access'}
</button>
<p className="text-sm text-gray-600 dark:text-gray-400 italic">
Drop a message in Discord to speed up the process
</p>
</div>
);
}

function getAnimationDuration() {
// the scrollSpeed input can be can be anywhere from 0 to 10. the
// lower the duration is, the faster the text scrolls. we divide by
Expand All @@ -239,80 +311,87 @@ function LedSign() {
return (11 - scrollSpeed);
}

const hasAccess = user.accessLevel >= membershipState.OFFICER;

return (
<div>
<div className="space-y-12 mt-10 gap-x-6 gap-y-8 w-full sm:grid-cols-6">
<div className="flex border-b border-gray-900/10 pb-12 md:w-full">
<div className="flex flex-col justify-center items-center sm:col-span-3 w-full">
<div className='w-2/3 lg:w-1/2'>
<label>Preview</label>
<div>
<div
className="led-sign-preview-border-top"
style={{ backgroundColor: borderColor }}
></div>
<div
className="led-sign-preview-background"
style={{ backgroundColor: backgroundColor }}
>
<div className="led-sign-marquee-container">
<div className="led-sign-marquee" style={{ animationDuration: `${getAnimationDuration()}s` }}>
<h1 className="led-sign-preview-text text-3xl" style={{ color: textColor }} placeholder="Sign Text">
{/*
{!hasAccess && (
<div className="flex justify-center items-center mt-10 w-full">
{renderPermissionRequestUI()}
</div>
)}
{hasAccess && (
<div className="space-y-12 mt-10 gap-x-6 gap-y-8 w-full sm:grid-cols-6">
<div className="flex border-b border-gray-900/10 pb-12 md:w-full">
<div className="flex flex-col justify-center items-center sm:col-span-3 w-full">
<div className='w-2/3 lg:w-1/2'>
<label>Preview</label>
<div>
<div
className="led-sign-preview-border-top"
style={{ backgroundColor: borderColor }}
></div>
<div
className="led-sign-preview-background"
style={{ backgroundColor: backgroundColor }}
>
<div className="led-sign-marquee-container">
<div className="led-sign-marquee" style={{ animationDuration: `${getAnimationDuration()}s` }}>
<h1 className="led-sign-preview-text text-3xl" style={{ color: textColor }} placeholder="Sign Text">
{/*
we add a padding of 28 characters of whitespace so the entire message
scrolls to the end of the preview before repeating. the preview has a
width of about 28 characters.
*/}
{text.padEnd(28, ' ')}
</h1>
{text.padEnd(28, ' ')}
</h1>
</div>
</div>
</div>
<div
className="led-sign-preview-border-bottom"
style={{ backgroundColor: borderColor }}
></div>
</div>
<div
className="led-sign-preview-border-bottom"
style={{ backgroundColor: borderColor }}
></div>
</div>
</div>
{maybeShowExpirationDate()}
{getExpirationButtonOrInput()}
{
inputArray.map(({
id,
title,
type,
value,
onChange,
...rest
}) => (
<div key={title} className="sm:col-span-2 sm:col-start-1 w-2/3 lg:w-1/2">
<div className="mt-2 ">
<label htmlFor="copies" className="block text-sm font-medium leading-6">{title}</label>
<input
type={type}
value={value}
id={id}
onChange={onChange}
className="indent-2 text-black dark:text-white block w-full rounded-md border-0 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-500 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
{...rest}
/>
{maybeShowExpirationDate()}
{getExpirationButtonOrInput()}
{
inputArray.map(({
id,
title,
type,
value,
onChange,
...rest
}) => (
<div key={title} className="sm:col-span-2 sm:col-start-1 w-2/3 lg:w-1/2">
<div className="mt-2 ">
<label htmlFor="copies" className="block text-sm font-medium leading-6">{title}</label>
<input
type={type}
value={value}
id={id}
onChange={onChange}
className="indent-2 text-black dark:text-white block w-full rounded-md border-0 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-500 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
{...rest}
/>
</div>
</div>
</div>
))
}
))
}

<button className='btn w-2/3 lg:w-1/2 bg-red-500 hover:bg-red-400 text-black mt-4' onClick={handleStop}>
<button className='btn w-2/3 lg:w-1/2 bg-red-500 hover:bg-red-400 text-black mt-4' onClick={handleStop}>
Stop
</button>
<button className='btn w-2/3 lg:w-1/2 bg-green-500 hover:bg-green-400 text-black mt-2' onClick={handleSend}>
</button>
<button className='btn w-2/3 lg:w-1/2 bg-green-500 hover:bg-green-400 text-black mt-2' onClick={handleSend}>
Send
</button>
{renderRequestStatus()}
</button>
{renderRequestStatus()}
</div>
</div>
</div>

</div>

)}
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const officerOrAdminRoutes = [
Component: LedSign,
path: '/led-sign',
pageName: 'LED Sign',
allowedIf: allowedIf.OFFICER_OR_ADMIN,
allowedIf: allowedIf.MEMBER,
redirect: '/',
inAdminNavbar: true
},
Expand Down