I'm having an issue and I don't find the answer by myself.
I'm trying to make the following code work. Actually it doesn't work in my Vue project.
const text = document.getElementById("text");
const phrases = [
"I'm John Doe",
"I'm student",
"I'm developer",
];
let currentPhraseIndex = 0;
let currentCharacterIndex = 0;
let currentPhrase = "";
let isDeleting = false;
function loop() {
const currentPhraseText = phrases[currentPhraseIndex];
if (!isDeleting) {
currentPhrase += currentPhraseText[currentCharacterIndex];
currentCharacterIndex++;
} else {
currentPhrase = currentPhrase.slice(0, -1);
currentCharacterIndex--;
}
text.innerHTML = currentPhrase;
if (currentCharacterIndex === currentPhraseText.length) {
isDeleting = true;
}
if (currentCharacterIndex === 0) {
currentPhrase = "";
isDeleting = false;
currentPhraseIndex++;
if (currentPhraseIndex === phrases.length) {
currentPhraseIndex = 0;
}
}
const spedUp = Math.random() * (80 - 50) + 50;
const normalSpeed = Math.random() * (300 - 200) + 200;
const time = isDeleting ? spedUp : normalSpeed;
setTimeout(loop, time);
}
loop();
<h2 id="text"></h2>
As you can see the code is actually working. Checkout the errors I have in my from my Vue Js project.
Do not hesitate, if you have any suggestions to improve my code according to Vue of course.
Try to put variables in data property and function in methods, or i composition api make variables reactive:
const { ref, reactive, onMounted } = Vue
const app = Vue.createApp({
setup() {
const opt = reactive({
currentPhraseIndex: 0,
currentCharacterIndex: 0,
currentPhrase: "",
isDeleting: false
})
const phrases = reactive([
"I'm John Doe",
"I'm student",
"I'm developer"
])
const text = ref('')
const loop = () => {
const currentPhraseText = phrases[opt.currentPhraseIndex];
if (!opt.isDeleting) {
opt.currentPhrase += currentPhraseText[opt.currentCharacterIndex];
opt.currentCharacterIndex++;
} else {
opt.currentPhrase = opt.currentPhrase.slice(0, -1);
opt.currentCharacterIndex--;
}
text.value = opt.currentPhrase;
if (opt.currentCharacterIndex === currentPhraseText.length) {
opt.isDeleting = true;
}
if (opt.currentCharacterIndex === 0) {
opt.currentPhrase = "";
opt.isDeleting = false;
opt.currentPhraseIndex++;
if (opt.currentPhraseIndex === opt.phrases?.length) {
opt.currentPhraseIndex = 0;
}
}
const spedUp = Math.random() * (80 - 50) + 50;
const normalSpeed = Math.random() * (300 - 200) + 200;
const time = opt.isDeleting ? spedUp : normalSpeed;
setTimeout(loop, time);
}
onMounted(() => {
loop()
})
return {
text
}
}
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<h2>{{ text }}</h2>
</div>
I found the way to make it work.
The following code is updated and works using Vue.js 3.
<script setup>
import { ref } from "vue";
const phrases = [
"I am John Doe.",
"I am student.",
"I am developer.",
];
const currentPhraseIndex = ref(0);
const currentCharacterIndex = ref(0);
const currentPhrase = ref("");
const isDeleting = ref(false);
function loop() {
const currentPhraseText = phrases[currentPhraseIndex.value];
if (!isDeleting.value) {
currentPhrase.value += currentPhraseText[currentCharacterIndex.value];
currentCharacterIndex.value++;
} else {
currentPhrase.value = currentPhrase.value.slice(0, -1);
currentCharacterIndex.value--;
}
if (currentCharacterIndex.value === currentPhraseText.length) {
isDeleting.value = true;
}
if (currentCharacterIndex.value === 0) {
currentPhrase.value = "";
isDeleting.value = false;
currentPhraseIndex.value++;
if (currentPhraseIndex.value === phrases.length) {
currentPhraseIndex.value = 0;
}
}
const spedUp = Math.random() * (80 - 50) + 50;
const normalSpeed = Math.random() * (300 - 200) + 200;
const time = isDeleting.value ? spedUp : normalSpeed;
setTimeout(loop, time);
}
loop();
</script>
<template>
<div>
<h1 id="title">{{ currentPhrase }}</h1>
</div>
</template>
You have to add this line
if (opt.currentCharacterIndex === currentPhraseText.length) {
opt.isDeleting = true;
opt.currentPhraseIndex = 0; // <===== you have to add this line
}
I'm implementing A*(A-star) algorithm in react.js but my program crashes whenever startNode(green) or destinationNode(blue) have more than one neighbour or if there is a cycle in the graph. There is something wrong when adding and deleting the neighbours from/to openList or when updating the parentId in the getPath() function. I cant even see the console because the website goes down.
Each node has: id, name, x, y, connectedToIdsList:[], gcost:Infinity, fcost:0, heuristic:0, parentId:null.
I'm sending the path to another component "TodoList" which prints out the path. My program should not return the path but keeps updating the path as i'm adding nodes and edges to the list. Please help, I've been stuck for hours now:/
My code:
export default class TurnByTurnComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = { shortestPath: [] }
}
render() {
const {
destinationLocationId,
locations,
originLocationId
} = this.props;
let path = []
if (destinationLocationId != null && originLocationId != null) {
if (originLocationId == destinationLocationId) { //check if the startNode node is the end node
return originLocationId;
}
var openList = [];
let startNode = getNodeById(originLocationId);
let destinationNode = getNodeById(destinationLocationId)
if (startNode.connectedToIds.length > 0 && destinationNode.connectedToIds.length > 0) { //check if start and destination nodes are connected first
startNode.gcost = 0
startNode.heuristic = manhattanDistance(startNode, destinationNode)
startNode.fcost = startNode.gcost + startNode.heuristic;
//perform A*
openList.push(startNode); //starting with the startNode
while (openList.length > 0) {
console.log("inside while")
var currentNode = getNodeOfMinFscore(openList); //get the node of the minimum f cost of all nodes in the openList
if (currentIsEqualDistanation(currentNode)) {
path = getPath(currentNode);
}
deleteCurrentFromOpenList(currentNode, openList);
for (let neighbourId of currentNode.connectedToIds) {
var neighbourNode = getNodeById(neighbourId);
currentNode.gcost = currentNode.gcost + manhattanDistance(currentNode, neighbourNode);
if (currentNode.gcost < neighbourNode.gcost) {
neighbourNode.parentId = currentNode.id; // keep track of the path
// total cost saved in neighbour.g
neighbourNode.gcost = currentNode.gcost;
neighbourNode.heuristic = manhattanDistance(neighbourNode, destinationNode);
neighbourNode.fcost = neighbourNode.gcost + neighbourNode.heuristic; //calculate f cost of the neighbourNode
addNeighbourNodeToOpenList(neighbourNode, openList);
}
}
}
path = path.reverse().join("->");
}
}
function addNeighbourNodeToOpenList(neighbourNode, openList) {
//add neighbourNode to the open list to be discovered later
if (!openList.includes(neighbourNode)) {
openList.push(neighbourNode);
}
}
function deleteCurrentFromOpenList(currNode, openList) {
const currIndex = openList.indexOf(currNode);
openList.splice(currIndex, 1); //deleting currentNode from openList
}
function currentIsEqualDistanation(currNode) {
//check if we reached out the distanation node
return (currNode.id == destinationLocationId)
}
function getNodeById(nid) {
var node;
for (let i = 0; i < locations.length; i++) {
if (locations[i].id == nid) {
node = locations[i]
}
}
return node
}
function getPath(destNode) {
console.log("inside getpath")
var parentPath = []
var parent;
while (destNode.parentId != null) {
parentPath.push(destNode.name)
parent = destNode.parentId;
destNode = getNodeById(parent);
}
//adding startNode to the path
parentPath.push(getNodeById(originLocationId).name)
return parentPath;
}
function getNodeOfMinFscore(openList) {
var minFscore = openList[0].fcost; //initValue
var nodeOfminFscore;
for (let i = 0; i < openList.length; i++) {
if (openList[i].fcost <= minFscore) {
minFscore = openList[i].fcost //minFvalue
nodeOfminFscore = openList[i]
}
}
return nodeOfminFscore
}
//manhattan distance is for heuristic and gScore. Here I use Manhattan instead of Euclidean
//because in this example we dont have diagnosal path.
function manhattanDistance(stNode, dstNode) {
var x = Math.abs(dstNode.x - stNode.x);
var y = Math.abs(dstNode.y - stNode.y);
var dist = x + y;
return dist;
}
return (
<div className="turn-by-turn-component">
<TodoList
list={"Shortest path: ", [path]}
/>
<TodoList
list={[]}
/>
</div>
);
}
}
TurnByTurnComponent.propTypes = {
destinationLocationId: PropTypes.number,
locations: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
connectedToIds: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
})),
originLocationId: PropTypes.number
};
Update new issue
Pictures of before and after linking a new node. When I update the graph and add a new node the path disappears. And sometimes come back and so on if I still add new nodes and edges to the graph. As I said, each node has: id, name, x, y, connectedToIdsList:[], gcost:Infinity, fcost:0, heuristic:0, parentId:null.
My new code now is:
export default class TurnByTurnComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = { shortestPath: [] }
}
render() {
const {
destinationLocationId,
locations,
originLocationId
} = this.props;
let path = []
if (destinationLocationId != null && originLocationId != null) {
console.log(JSON.stringify(locations))
path = [getNodeById(originLocationId).namne];
if (originLocationId != destinationLocationId) {
var openList = [];
let startNode = getNodeById(originLocationId);
let destinationNode = getNodeById(destinationLocationId)
if (startNode.connectedToIds.length > 0 && destinationNode.connectedToIds.length > 0) {
startNode.gcost = 0
startNode.heuristic = manhattanDistance(startNode, destinationNode)
startNode.fcost = startNode.gcost + startNode.heuristic;
openList.push(startNode); //starting with the startNode
while (openList.length > 0) {
var currentNode = getNodeOfMinFscore(openList); //get the node of the minimum f cost of all nodes in the openList
if (currentIsEqualDistanation(currentNode)) {
path = getPath(currentNode);
break;
}
deleteCurrentFromOpenList(currentNode, openList);
for (let neighbourId of currentNode.connectedToIds) {
var neighbourNode = getNodeById(neighbourId);
let gcost = currentNode.gcost + manhattanDistance(currentNode, neighbourNode);
if (gcost < (neighbourNode.gcost ?? Infinity)) {
neighbourNode.parentId = currentNode.id;
// keep track of the path
// total cost saved in neighbour.g
neighbourNode.gcost = gcost;
neighbourNode.heuristic = manhattanDistance(neighbourNode, destinationNode);
neighbourNode.fcost = neighbourNode.gcost + neighbourNode.heuristic; //calculate f cost of the neighbourNode
addNeighbourNodeToOpenList(neighbourNode, openList);
}
}
}
}
}
}
path = path.reverse().join("->");
function addNeighbourNodeToOpenList(neighbourNode, openList) {
//add neighbourNode to the open list to be discovered later
if (!openList.includes(neighbourNode)) {
openList.push(neighbourNode);
}
}
function deleteCurrentFromOpenList(currentNode, openList) {
const currIndex = openList.indexOf(currentNode);
openList.splice(currIndex, 1); //deleting currentNode from openList
}
function currentIsEqualDistanation(currentNode) {
//check if we reached out the distanation node
return (currentNode.id == destinationLocationId)
}
function getNodeById(id) {
var node;
for (let i = 0; i < locations.length; i++) {
if (locations[i].id == id) {
node = locations[i]
}
}
return node
}
function getPath(destinationNode) {
console.log("inside getpath")
var parentPath = []
var parent;
while (destinationNode.parentId != null) {
parentPath.push(destinationNode.name)
parent = destinationNode.parentId;
destinationNode = getNodeById(parent);
}
//adding startNode to the path
parentPath.push(getNodeById(originLocationId).name)
return parentPath;
}
function getNodeOfMinFscore(openList) {
var minFscore = openList[0].fcost; //initValue
var nodeOfminFscore;
for (let i = 0; i < openList.length; i++) {
if (openList[i].fcost <= minFscore) {
minFscore = openList[i].fcost //minFvalue
nodeOfminFscore = openList[i]
}
}
return nodeOfminFscore
}
//manhattan distance is for heuristic and gScore. Here I use Manhattan instead of Euclidean
//because in this example we dont have diagnosal path.
function manhattanDistance(startNode, destinationNode) {
var x = Math.abs(destinationNode.x - startNode.x);
var y = Math.abs(destinationNode.y - startNode.y);
var dist = x + y;
return dist;
}
return (
<div className="turn-by-turn-component">
<TodoList
title="Mandatory work"
list={[path]}
/>
<TodoList
title="Optional work"
list={[]}
/>
</div>
);
}
}
TurnByTurnComponent.propTypes = {
destinationLocationId: PropTypes.number,
locations: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
connectedToIds: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
})),
originLocationId: PropTypes.number
};
There are a few issues in your code:
return originLocationId; should not happen. When the source is equal to the target, then set the path, and make sure the final return of this function is executed, as you want to return the div element.
When the target is found in the loop, not only should the path be built, but the loop should be exited. So add a break
currentNode.gcost = currentNode.gcost + manhattanDistance(currentNode, neighbourNode); is not right: you don't want to modify currentNode.gcost: its value should not depend on the outgoing edge to that neighbour. Instead store this sum in a temporary variable (like gcost)
The comparison with neighbourNode.gcost will not work when that node does not yet have a gcost member. I don't see in your code that it got a default value that makes sure this condition is true, so you should use a default value here, like (neighbourNode.gcost ?? Infinity)
path = path.reverse().join("->"); should better be executed always, also when there is no solution (so path is a string) or when the source and target are the same node.
Here is a corrected version, slightly adapted to run here as a runnable snippet:
function render() {
const {
destinationLocationId,
locations,
originLocationId
} = this.props;
let path = [];
if (destinationLocationId != null && originLocationId != null) {
path = [originLocationId]; // The value for when the next if condition is not true
if (originLocationId != destinationLocationId) {
var openList = [];
let startNode = getNodeById(originLocationId);
let destinationNode = getNodeById(destinationLocationId)
if (startNode.connectedToIds.length > 0 && destinationNode.connectedToIds.length > 0) {
startNode.gcost = 0
startNode.heuristic = manhattanDistance(startNode, destinationNode)
startNode.fcost = startNode.gcost + startNode.heuristic;
openList.push(startNode);
while (openList.length > 0) {
var currentNode = getNodeOfMinFscore(openList);
if (currentIsEqualDistanation(currentNode)) {
path = getPath(currentNode);
break; // Should end the search here!
}
deleteCurrentFromOpenList(currentNode, openList);
for (let neighbourId of currentNode.connectedToIds) {
var neighbourNode = getNodeById(neighbourId);
// Should not modify the current node's gcost. Use a variable instead:
let gcost = currentNode.gcost + manhattanDistance(currentNode, neighbourNode);
// Condition should also work when neighbour has no gcost yet:
if (gcost < (neighbourNode.gcost ?? Infinity)) {
neighbourNode.parentId = currentNode.id;
neighbourNode.gcost = gcost; // Use the variable
neighbourNode.heuristic = manhattanDistance(neighbourNode, destinationNode);
neighbourNode.fcost = neighbourNode.gcost + neighbourNode.heuristic;
addNeighbourNodeToOpenList(neighbourNode, openList);
}
}
}
}
}
}
// Convert the path to string in ALL cases:
path = path.reverse().join("->");
function addNeighbourNodeToOpenList(neighbourNode, openList) {
if (!openList.includes(neighbourNode)) {
openList.push(neighbourNode);
}
}
function deleteCurrentFromOpenList(currNode, openList) {
const currIndex = openList.indexOf(currNode);
openList.splice(currIndex, 1);
}
function currentIsEqualDistanation(currNode) {
return (currNode.id == destinationLocationId)
}
function getNodeById(nid) {
var node;
for (let i = 0; i < locations.length; i++) {
if (locations[i].id == nid) {
node = locations[i]
}
}
return node
}
function getPath(destNode) {
var parentPath = []
var parentId;
while (destNode.parentId != null) {
parentPath.push(destNode.name)
parentId = destNode.parentId;
destNode = getNodeById(parentId);
}
parentPath.push(getNodeById(originLocationId).name)
return parentPath;
}
function getNodeOfMinFscore(openList) {
var minFscore = openList[0].fcost;
var nodeOfminFscore;
for (let i = 0; i < openList.length; i++) {
if (openList[i].fcost <= minFscore) {
minFscore = openList[i].fcost
nodeOfminFscore = openList[i]
}
}
return nodeOfminFscore
}
function manhattanDistance(stNode, dstNode) {
var x = Math.abs(dstNode.x - stNode.x);
var y = Math.abs(dstNode.y - stNode.y);
var dist = x + y;
return dist;
}
return "Shortest path: " + path;
}
// Demo
let props = {
locations: [
{ id: 1, x: 312, y: 152, connectedToIds: [4,2], name: "Thetaham" },
{ id: 2, x: 590, y: 388, connectedToIds: [1,3], name: "Deltabury" },
{ id: 3, x: 428, y: 737, connectedToIds: [2], name: "Gammation" },
{ id: 4, x: 222, y: 430, connectedToIds: [1], name: "Theta City" },
],
originLocationId: 1,
destinationLocationId: 3,
};
console.log(render.call({props}));
I am trying to do something with my UI. for that I am trying to convert the below code to ES6 code. Can anyone please help me? I tried from my side. but don't know where I am getting the error.
const progress = document.getElementById('progress')
const prev = document.getElementById('prev')
const next = document.getElementById('next')
const circles = document.querySelectorAll('.circle')
let currentActive = 1
next.addEventListener('click', () => {
currentActive++;
if(currentActive > circles.length) {
currentActive = circles.length
}
update()
})
prev.addEventListener('click', () => {
currentActive--
if(currentActive < 1) {
currentActive = 1
}
update()
})
function update() {
circles.forEach((circle, idx) => {
if(idx < currentActive) {
circle.classList.add('active')
} else {
circle.classList.remove('active')
}
})
const actives = document.querySelectorAll('.active')
progress.style.width = (actives.length - 1) / (circles.length - 1) * 100 + '%'
if(currentActive === 1) {
prev.disabled = true
} else if(currentActive === circles.length) {
next.disabled = true
} else {
prev.disabled = false
next.disabled = false
}
}
please let me know.
class abcd{
}
I am a student studying JavaScript.
I found the js code for the scrambled text animation, but I want to stop looping.
(Because I want to read the contents)
Anyone can explain to stop looping in the 'for or if' part?
Also, are there any unnecessary parts of the JavaScript code?
Thanks in advance for the answer.
html
// ——————————————————————————————————————————————————
// TextScramble
// ——————————————————————————————————————————————————
class TextScramble {
constructor(el) {
this.el = el
this.chars = 'かきくけこらりるれろ'
this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText
const length = Math.max(oldText.length, newText.length)
const promise = new Promise((resolve) => this.resolve = resolve)
this.queue = []
for (let i = 0; i < length; i++) {
const from = oldText[i] || ''
const to = newText[i] || ''
const start = Math.floor(Math.random() * 40)
const end = start + Math.floor(Math.random() * 40)
this.queue.push({
from,
to,
start,
end
})
}
cancelAnimationFrame(this.frameRequest)
this.frame = 0
this.update()
return promise
}
update() {
let output = ''
let complete = 0
for (let i = 0, n = this.queue.length; i < n; i++) {
let {
from,
to,
start,
end,
char
} = this.queue[i]
if (this.frame >= end) {
complete++
output += to
} else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
char = this.randomChar()
this.queue[i].char = char
}
output += `<span class="dud">${char}</span>`
} else {
output += from
}
}
this.el.innerHTML = output
if (complete === this.queue.length) {
this.resolve()
} else {
this.frameRequest = requestAnimationFrame(this.update)
this.frame++
}
}
randomChar() {
return this.chars[Math.floor(Math.random() * this.chars.length)]
}
}
// ——————————————————————————————————————————————————
// Example
// ——————————————————————————————————————————————————
const phrases = [
'ロレム・イプサムの嘆き、トマト大好き学部のエリット、しかし時と活力、そのような労働と悲しみ、ブラインド行うにはいくつかの重要な事柄に座ります。長年にわたり、私は学区と長寿であれば、そのような刺激の取り組み、彼女のうち、運動の利点を分注を邪魔されたする人が来ます。クピダタットのつるの痛みになりたい宿題に、批判されてきたら痛み、マグナ逃亡しても結果の喜びを生成しません。先例クピダタットブラックは先例していない、つまり、彼らはあなたの悩みに責任がある人の、一般的な義務を捨て、魂を癒しています。'
]
const el = document.querySelector('.text')
const fx = new TextScramble(el)
let counter = 0
const next = () => {
fx.setText(phrases[counter]).then(() => {
setTimeout(next, 800)
})
counter = (counter + 1) % phrases.length
}
next()
<div id="main">
<div class="container">
<div class="glitch" data-text="About">About</div>
<div class="glow">About</div>
</div>
<div class="scanlines"></div>
<div class="text"></div>
</div>
I think you should try adding delay in your loop
see if this helps you
for (let i=0; i<10; i++) {
task(i);
}
function task(i) {
setTimeout(function() {
// Add tasks to do
}, 2000 * i);
}
I'm getting a warning in my browser when I am trying to set the state of my context provider. The warning in the browser console is:
Warning: Cannot update a component (`DataContextProvider`) while rendering a different component (`PastLeaveReqUpperLinks`).
How do I go about finding this? I think I need to apply useEffect() hooks to my set methods, but when I try, it says I cannot use a hook inside a callback.
My code is below - I think the issue lies within the modal (commented with MODAL START) - notably the setUnderlayShow() and modalOnOff() set functions that set the state of the context provider.
import React, { useContext, useEffect, useState } from 'react';
import { DataContext } from '../../contexts/DataContext';
import axios from 'axios';
import '../../styles/leaveRequests.css';
import loader from '../../img/unitIcons/loader.svg';
import tick from '../../img/unitIcons/tick.svg';
import cross from '../../img/unitIcons/cross.svg';
import close from '../../img/modals/close.svg';
import '../../styles/modals.css';
const PastLeaveRequestsUnits = () => {
const {
underlayShow,
setUnderlayShow,
modalState,
modalOnOff,
requests,
} = useContext(DataContext);
// - - - - - M O D A L - S T A R T - - - - -
// modalOnOff is a fct in the DataContext which turns modal on/off
// is it also used in LeaveReqsPage.js for the underlay element
// modal: store selected unit for modal to use to determine which data
let [selectedUnit, setSelectedUnit] = useState('');
let updateSelectedUnit = (item) => {
setSelectedUnit(item);
};
// modal - open: fct to update the modalState and update selected unit
const openModal = (item) => {
updateSelectedUnit(item);
modalOnOff();
// uses DataContext's underlay state
setUnderlayShow(!underlayShow);
};
// modal - close: fct to update the modalState and update selected unit
const closeModal = (item) => {
updateSelectedUnit(item);
modalOnOff();
setUnderlayShow(!underlayShow);
};
// - - - - - M O D A L - E N D - - - - -
// COMBINE ALL LEAVE TYPES
// map through all requests and store each request into a new array
let allRequests = [];
if (requests.annualLeave) {
requests.annualLeave.forEach((item) => {
allRequests.push(item);
});
}
if (requests.tilRequest) {
requests.tilRequest.forEach((item) => {
allRequests.push(item);
});
}
if (requests.customReq) {
requests.customReq.forEach((item) => {
allRequests.push(item);
});
}
// sort requests array by startdate
var sortedRequests = allRequests.sort(function (a, b) {
return a.start == b.start ? 0 : +(a.start > b.start) || -1;
});
// Mapper: map through leave units
const getLeaveUnits = sortedRequests.map((item) => {
// determine unit colour
let unitColour = '';
if (item.approved === null) {
unitColour = 'unit reqPending';
} else if (item.approved === true) {
unitColour = 'unit reqApproved';
} else if (item.approved === false) {
unitColour = 'unit reqDeclined';
}
// determine status icon
let statusIcon = loader;
if (item.approved === null) {
statusIcon = loader;
} else if (item.approved === true) {
statusIcon = tick;
} else {
statusIcon = cross;
}
// determine leave type name
let leaveTypeName = '';
if (item.type === 'annualLeave') {
leaveTypeName = 'Annual Leave';
} else if (item.type === 'tilRequest') {
leaveTypeName = 'Time in Lieu';
} else {
leaveTypeName = item.type;
}
// rounder fct for use in convertTimestamp()
const rounder = (num, rounder) => {
var multiplier = 1 / rounder;
return Math.round(num * multiplier) / multiplier;
};
// convert timestamp
const convertTimestamp = (timestamp, type) => {
let days = timestamp / 1000 / 60 / 60 / 24;
// for A/L leave types
if (type === 'annualLeave') {
let value = rounder(days, 0.5);
let d = 'days';
if (value === 1) {
d = 'day';
}
if (value < 0.5) {
return `0.5 days`;
} else {
return `${value} ${d}`;
}
// for til leave types
} else if (type === 'tilRequest') {
let mins = Math.floor(timestamp / 1000 / 60);
if (mins > 59) {
let hours = Math.floor(mins / 60);
let modul = mins % (hours * 60);
if (modul > 0) {
return `${hours}h ${modul}m`;
} else {
return `${hours}h`;
}
} else {
return `${mins} mins`;
}
} else {
let days = timestamp / 1000 / 60 / 60 / 24;
let value = rounder(days, 0.5);
let d = 'days';
if (value === 1) {
d = 'day';
}
if (value < 0.5) {
return `0.5 days`;
} else {
return `${value} ${d}`;
}
}
};
// start & end date formatter
const startEndDate = (start, end) => {
// removed irrelevant code
return `${startDay} ${startMonth} ${startYr} ${divider} ${endDay} ${endMonth} ${endYr}`;
};
// if unit is older than today, show
// today as a timestamp
let today = Math.round(new Date().getTime());
// if modal open, scroll-lock the requests container
// if (modalState) {
// $('.innerUnitsContainer').css('overflow', 'hidden');
// } else {
// $('.innerUnitsContainer').css('overflow', 'auto');
// }
// modal: template
const modal = () => {
let status = '';
// need to make a function to return name of manager
let manager = 'Sean Wheldon';
let submitDate = () => {
let dateObj = new Date(selectedUnit.submitDate);
let day = dateObj.toLocaleString('en-US', { day: 'numeric' });
let month = dateObj.toLocaleString('en-US', { month: 'short' });
return `${day} ${month}`;
};
if (selectedUnit.approved === true) {
status = `Approved by ${manager}`;
} else if (selectedUnit.approved === null) {
status = `Submitted on ${submitDate()}`;
} else if (selectedUnit.approved === false) {
status = `Declined by ${manager}`;
}
let editButton = () => {
if (selectedUnit.approved !== false) {
return <p className='editButton'>EDIT REQUEST</p>;
}
};
return (
<div>
<img
src={close}
className='closeBtn'
onClick={closeModal}
alt='Close'
/>
<p className='modalTitle'>
{startEndDate(selectedUnit.start, selectedUnit.end)}
</p>
<p className='requestStatus'>{status}</p>
<div onClick={closeModal}>{editButton()}</div>
</div>
);
};
if (item.end <= today && item.approved !== false) {
return (
<div
className={unitColour}
key={item.reqID}
onClick={() => {
openModal(item);
}}
>
<div className='unitLeft'>
<img src={statusIcon} alt='Status Icon' id='statusIcon' />
</div>
<div className='unitMiddle'>
<p id='unitLeaveType'>{leaveTypeName}</p>
<p id='unitDate'>{startEndDate(item.start, item.end)}</p>
</div>
<div className='unitDivider'></div>
<div className='unitRight'>
<p id='unitDuration'>
{convertTimestamp(item.duration, item.type)}
</p>
</div>
{/* M O D A L */}
<div
className={`modalBackground ${!!modalState ? 'open' : ''}`}
onClick={(e) => {
e.stopPropagation();
}}
>
{modal()}
</div>
{/* E N D M O D A L */}
</div>
);
}
});
// render
return <div className='requestsContainer'>{getLeaveUnits}</div>;
};
export default PastLeaveRequestsUnits;