yup-live-chrome-extension/src/components/RateSingle.svelte

248 lines
10 KiB
Svelte
Raw Normal View History

2023-02-13 19:20:50 +00:00
<script lang="ts">
import { mainStore } from '@/utils/store';
import { hasVote, getPost } from '@/utils/votes';
import { onMount } from 'svelte'
import { formatNumber } from '@/utils/misc'
import { fetchWAuth } from '@/utils/auth'
import { alertStore } from '@/utils/store';
import { API_BASE } from '@/constants/config';
import { executeVote } from '@/utils/votes';
export let url = ''
export let disabled = false
let loading = true
const defaultUserVote = {
rating: 0,
like: null,
_id: null
}
let userVote = defaultUserVote
let saveUserVote = defaultUserVote
let positiveWeight = 0
let negativeWeight = 0
let savePositiveWeight = 0
let saveNegativeWeight = 0
let timer = 0
let doingVote = false
let post = null
let delLoading = false
const getPostIntial = async (onlyPost = false) => {
post = await getPost(url)
if(!post) {
loading = false
} else {
positiveWeight = Math.trunc(post.rawPositiveWeight ?? 0 as number)
negativeWeight = Math.trunc(post.rawNegativeWeight ?? 0 as number)
savePositiveWeight = positiveWeight
saveNegativeWeight = negativeWeight
if(!onlyPost) {
const has = (await hasVote(post._id.postid, $mainStore.user.auth.userId))?.[0] ?? null
if(has){
userVote = has
saveUserVote = has
}
} else {
userVote = defaultUserVote
saveUserVote = defaultUserVote
}
}
}
onMount(async () => {
if(disabled) {
loading = false
return
}
if(!url) {
loading = false
disabled = true
return
}
await getPostIntial()
loading = false
})
const doVote = (type = true) => {
if(disabled) {
$alertStore?.show('You shall not pass', 'error')
return
}
if(timer && !doingVote) {
clearTimeout(timer)
}
let noVoteAlert = false
if(!doingVote) {
const lastRating = userVote?.rating ?? 1
let sameType = true
if(type !== userVote?.like && userVote._id !== null) {
userVote.rating = 0
sameType = false
}
if(type && userVote?.rating < 3 || !type && userVote?.rating < 2) {
userVote.rating += 1
}
if(userVote?.rating === lastRating && userVote && sameType) {
$alertStore?.show('You already gave maximum rating.', 'warning')
noVoteAlert = true
} else {
if(userVote.like !== type && userVote._id !== null) {
if(type) {
negativeWeight -= $mainStore.user.profile.yup.weight * (userVote.rating + lastRating - 1)
userVote.rating = 1
positiveWeight += $mainStore.user.profile.yup.weight * userVote.rating
} else {
positiveWeight -= $mainStore.user.profile.yup.weight * (userVote.rating + lastRating - 1)
userVote.rating = 1
negativeWeight += $mainStore.user.profile.yup.weight * userVote.rating
}
} else {
if(type) {
positiveWeight += $mainStore.user.profile.yup.weight * (userVote.rating - lastRating)
} else {
negativeWeight += $mainStore.user.profile.yup.weight * (userVote.rating - lastRating)
}
}
userVote.like = type
}
timer = setTimeout(async () => {
doingVote = true
let reqVote
try {
reqVote = await executeVote({
post,
userVote,
$mainStore,
$alertStore,
url,
noVoteAlert
})
if(!reqVote) {
throw new Error('Vote not executed')
}
savePositiveWeight = positiveWeight
saveNegativeWeight = negativeWeight
saveUserVote = userVote
} catch(e) {
console.log(e)
positiveWeight = savePositiveWeight
negativeWeight = saveNegativeWeight
userVote = saveUserVote
}
if(reqVote) {
userVote = reqVote
}
doingVote = false
}, 500) as unknown as number
}
}
const deleteVote = async () => {
if(delLoading) {
return
}
try {
doingVote = true
delLoading = true
const reqVote = await fetch(`${API_BASE}/votes/post/${post._id.postid}/voter/${$mainStore.user.auth.userId}`)
const voteId = (await reqVote.json())[0]._id.voteid
const p1 = fetchWAuth($mainStore, `${API_BASE}/votes/${voteId}`, {
method: 'DELETE'
})
const [req] = await Promise.all([p1])
if (req.ok) {
await getPostIntial(true)
$alertStore.show('Vote deleted!')
} else {
$alertStore.show('Vote not deleted due to error try to re-login!', 'error')
positiveWeight = savePositiveWeight
negativeWeight = saveNegativeWeight
userVote = saveUserVote
}
doingVote = false
delLoading = false
} catch (error) {
positiveWeight = savePositiveWeight
negativeWeight = saveNegativeWeight
userVote = saveUserVote
console.log(error)
$alertStore.show('The vote could not be deleted!')
delLoading = false
doingVote = false
}
}
</script>
{#if userVote._id !== null}
<svg on:click={() => deleteVote()} aria-hidden="true" class="{`w-4 opacity-30 delete interactive-svg ${delLoading ? 'animate-ping' : ''}`}" viewBox="0 0 512 512"><title/><polygon points="337.46 240 312 214.54 256 270.54 200 214.54 174.54 240 230.54 296 174.54 352 200 377.46 256 321.46 312 377.46 337.46 352 281.46 296 337.46 240" style="fill:none"/><polygon points="337.46 240 312 214.54 256 270.54 200 214.54 174.54 240 230.54 296 174.54 352 200 377.46 256 321.46 312 377.46 337.46 352 281.46 296 337.46 240" style="fill:none"/><path d="M64,160,93.74,442.51A24,24,0,0,0,117.61,464H394.39a24,24,0,0,0,23.87-21.49L448,160ZM312,377.46l-56-56-56,56L174.54,352l56-56-56-56L200,214.54l56,56,56-56L337.46,240l-56,56,56,56Z"/><rect height="80" rx="12" ry="12" width="448" x="32" y="48"/></svg>
{/if}
<div class="{`flex justify-center main-section bt ${doingVote ? 'animate-pulse disabled' : ''}`}" class:disabled>
<div on:click={() => doVote(true)} aria-hidden="true" class="{`flex w-1/2 p-4 box h-6 bf mr-4 ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}">
{#if userVote.rating && userVote.like}
<svg class="w-8" viewBox="0 0 24 24">
<path fill="#fff" d="M12,3.172L5.586,9.586c-0.781,0.781-0.781,2.047,0,2.828s2.047,0.781,2.828,0L10,10.828v7.242c0,1.104,0.895,2,2,2 c1.104,0,2-0.896,2-2v-7.242l1.586,1.586C15.977,12.805,16.488,13,17,13s1.023-0.195,1.414-0.586c0.781-0.781,0.781-2.047,0-2.828 L12,3.172z"/>
</svg>
{:else}
<svg class="w-8" viewBox="0 0 24 24"><g><path fill="#fff" d="M12,21c-1.654,0-3-1.346-3-3v-4.764c-1.143,1.024-3.025,0.979-4.121-0.115c-1.17-1.169-1.17-3.073,0-4.242L12,1.758 l7.121,7.121c1.17,1.169,1.17,3.073,0,4.242c-1.094,1.095-2.979,1.14-4.121,0.115V18C15,19.654,13.654,21,12,21z M11,8.414V18 c0,0.551,0.448,1,1,1s1-0.449,1-1V8.414l3.293,3.293c0.379,0.378,1.035,0.378,1.414,0c0.391-0.391,0.391-1.023,0-1.414L12,4.586 l-5.707,5.707c-0.391,0.391-0.391,1.023,0,1.414c0.379,0.378,1.035,0.378,1.414,0L11,8.414z"/></g>
</svg>
{/if}
{#key positiveWeight}
<span class="ml-4">{formatNumber(positiveWeight)}</span>
{/key}
</div>
<div on:click={() => doVote(false)} aria-hidden="true" class="{`flex w-1/2 p-4 box h-6 bf ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}">
{#if userVote.rating && !userVote.like}
<svg class="w-8 down" viewBox="0 0 24 24">
<path fill="#fff" d="M12,3.172L5.586,9.586c-0.781,0.781-0.781,2.047,0,2.828s2.047,0.781,2.828,0L10,10.828v7.242c0,1.104,0.895,2,2,2 c1.104,0,2-0.896,2-2v-7.242l1.586,1.586C15.977,12.805,16.488,13,17,13s1.023-0.195,1.414-0.586c0.781-0.781,0.781-2.047,0-2.828 L12,3.172z"/>
</svg>
{:else}
<svg class="w-8 down" viewBox="0 0 24 24"><g><path fill="#fff" d="M12,21c-1.654,0-3-1.346-3-3v-4.764c-1.143,1.024-3.025,0.979-4.121-0.115c-1.17-1.169-1.17-3.073,0-4.242L12,1.758 l7.121,7.121c1.17,1.169,1.17,3.073,0,4.242c-1.094,1.095-2.979,1.14-4.121,0.115V18C15,19.654,13.654,21,12,21z M11,8.414V18 c0,0.551,0.448,1,1,1s1-0.449,1-1V8.414l3.293,3.293c0.379,0.378,1.035,0.378,1.414,0c0.391-0.391,0.391-1.023,0-1.414L12,4.586 l-5.707,5.707c-0.391,0.391-0.391,1.023,0,1.414c0.379,0.378,1.035,0.378,1.414,0L11,8.414z"/></g>
</svg>
{/if}
{#key negativeWeight}
<span class="ml-4">{formatNumber(negativeWeight)}</span>
{/key}
</div>
</div>
<style lang="scss">
.cursor-block {
cursor: not-allowed;
}
.cursor-pointer {
cursor: pointer;
}
.box {
box-shadow: inset 3px -3px 6rem 11px #0000005e;
}
.bf {
border: 1px solid #d3d9dfc2;
border-radius: 6px;
transition: all 0.2s ease-in-out;
}
.bf:hover {
color: #fffee5;
background-color: #0000004f;
border: 1px solid #d3d9df73;
}
.down {
transform: rotate(180deg);
}
.delete {
position: absolute;
top: 225px;
right: 7px;
fill: #f0f8ff;
}
</style>