server/frontend/fic/src/routes/[theme]/[exercice]/+page.svelte

291 lines
13 KiB
Svelte

<script>
import {
Alert,
Badge,
Button,
Card,
CardBody,
CardHeader,
CardText,
Col,
Icon,
Row,
Spinner,
} from '@sveltestrap/sveltestrap';
import ExerciceDownloads from '$lib/components/ExerciceDownloads.svelte';
import ExerciceFlags from '$lib/components/ExerciceFlags.svelte';
import ExerciceHints from '$lib/components/ExerciceHints.svelte';
import ExerciceSolved from '$lib/components/ExerciceSolved.svelte';
import ExerciceVideo from '$lib/components/ExerciceVideo.svelte';
import ResolutionModal from '$lib/components/ResolutionModal.svelte';
import { current_exercice } from '$lib/stores/exercices';
import { my } from '$lib/stores/my';
import { current_theme } from '$lib/stores/themes';
import { settings } from '$lib/stores/settings';
import { waitDiff, waitInProgress } from '$lib/wait.js';
let solved = {};
let openResolution = false;
async function askProgressReset() {
waitInProgress.set(true);
const response = await fetch(
"reset_progress",
{
method: "POST",
headers: {'Accept': 'application/json'},
body: JSON.stringify({"eid": $current_exercice.id}),
}
);
if (response.status < 300) {
waitDiff(13, $my.exercices[$current_exercice.id]);
} else {
data = await response.json();
waitInProgress.set(false);
alert("Quelque chose s'est mal passé : " + data.errmsg);
}
}
</script>
{#if $current_exercice}
<Card body class="niceborder text-indent my-3">
{#if $current_theme.locked}
<div style="position: absolute; z-index: 0; top: 0; bottom: 0; left: 0; right: 0;" class="d-flex justify-content-center align-items-center">
<div style="transform: rotate(-25deg)">
<div class="display-3 font-weight-bolder border border-danger text-danger px-3 py-1" style="opacity: 0.5; border-radius: 20px; border-width: 5px !important; font-family: 'Courier New'">
CONFIDENTIEL
</div>
</div>
</div>
{/if}
<h3 class="display-4">{$current_exercice.title}</h3>
<div>
{#each $current_exercice.tags as tag, index}
<Badge href="tags/{tag}" pill color="secondary" class="mx-1 mb-2" >#{tag}</Badge>
{/each}
</div>
{#if !$my || !$my.exercices[$current_exercice.id]}
<p class="lead text-justify">{@html $current_exercice.headline}</p>
{:else}
{#if $my.exercices[$current_exercice.id].wip}
<Alert color="warning">
<Icon name="cone-striped" />
<strong>
Cette étape est marquée comme étant en cours d'élaboration.
</strong>
Elle n'est pas prête à être tentée. Vous devriez directement passer à l'étape suivante.
</Alert>
{/if}
<p class="lead text-justify">{@html $my.exercices[$current_exercice.id].statement}</p>
{#if $my.exercices[$current_exercice.id].issue}
<Alert color="{$my.exercices[$current_exercice.id].issuekind}">
{@html $my.exercices[$current_exercice.id].issue}
</Alert>
{/if}
{/if}
<hr class="mt-0 mb-4">
<Row>
<Col>
<Row class="level" cols={{xs:2, md:3, xl:4}}>
<Col>
<div class="level-item">
{#if $settings.discountedFactor > 0 && $my && $my.exercices[$current_exercice.id]}
<div class="heading">
Cote
</div>
{:else}
<div class="heading">
Gain
</div>
{/if}
<div class="value">
{#if $settings.discountedFactor && $current_exercice.solved}
<!-- This display the number of points gained by the team if it validates the exercice (current teams have more points than that) -->
{Math.trunc($current_exercice.gain * (1-$settings.discountedFactor*$current_exercice.solved)*10)/10} {$current_exercice.gain==1?"point":"points"}
{:else}
{$current_exercice.gain} {$current_exercice.gain==1?"point":"points"}
{/if}
</div>
{#if $settings.firstBlood && $current_exercice.solved < 1}
<div class="text-muted">
<em>+{$settings.firstBlood * 100}% (prem's)</em>
</div>
{:else if $settings.discountedFactor > 0 && $my && $my.exercices[$current_exercice.id]}
<div class="text-muted">
<em>initialement {$current_exercice.gain} {$current_exercice.gain==1?"point":"points"}</em>
</div>
{/if}
{#if $current_exercice.curcoeff != 1.0 || $settings.exerciceCurrentCoefficient != 1.0}
<div class="text-muted">
<em>{#if $current_exercice.curcoeff * $settings.exerciceCurrentCoefficient > 1}+{Math.round(($current_exercice.curcoeff * $settings.exerciceCurrentCoefficient - 1) * 100)}{:else}-{Math.round((1-($current_exercice.curcoeff * $settings.exerciceCurrentCoefficient)) * 100)}{/if}% (bonus)</em>
</div>
{/if}
</div>
</Col>
<Col class="d-none d-md-block">
<div class="level-item">
<div class="heading">
Tenté par
</div>
<div class="value">
{#if !$current_exercice.tried}
aucune équipe
{:else}
{$current_exercice.tried} {$current_exercice.tried == 1?"équipe":"équipes"}
{#if $my && $my.exercices[$current_exercice.id] && $my.exercices[$current_exercice.id].total_tries}
(cumulant {$my.exercices[$current_exercice.id].total_tries} {$my.exercices[$current_exercice.id].total_tries == 1?"tentative":"tentatives"})
{/if}
{/if}
</div>
</div>
</Col>
<Col class="d-none d-md-block">
<div class="level-item">
<div class="heading">
Résolu par
</div>
<div class="value">
{#if !$current_exercice.solved}
aucune équipe
{:else}
{$current_exercice.solved} {$current_exercice.solved == 1?"équipe":"équipes"}
{/if}
</div>
</div>
</Col>
<Col class="d-block d-md-none">
<div class="level-item">
<div class="heading">
{#if !$current_exercice.solved}
Tenté par
{:else}
Résolu par
{/if}
</div>
<div class="value">
{#if !$current_exercice.solved}
{#if !$current_exercice.tried}
aucune équipe
{:else}
{$current_exercice.tried} {$current_exercice.tried == 1?"équipe":"équipes"}
{#if $my && $my.exercices[$current_exercice.id] && $my.exercices[$current_exercice.id].total_tries}
(cumulant {$my.exercices[$current_exercice.id].total_tries} {$my.exercices[$current_exercice.id].total_tries == 1?"tentative":"tentatives"})
{/if}
{/if}
{:else}
{$current_exercice.solved} {$current_exercice.solved == 1?"équipe":"équipes"}
{/if}
</div>
</div>
</Col>
</Row>
</Col>
{#if $my && $my.team_id}
<Col xs="auto" class="d-flex flex-column justify-content-between">
{#if $settings.acceptNewIssue}
<a href="issues/?eid={$current_exercice.id}" class="btn btn-sm btn-warning">
<Icon name="bug" />
Rapporter une anomalie sur ce défi
</a>
{/if}
{#if $settings.QAenabled}
<a href="qa/exercices/{$current_exercice.id}" class="btn btn-sm btn-info" target="_self">
<Icon name="bug" />
Voir les éléments QA sur ce défi
</a>
{/if}
{#if $settings.wip && $settings.canResetProgress}
<Button size="sm" color="dark" on:click={askProgressReset} disabled={!$my.exercices[$current_exercice.id].solved_time || $waitInProgress}>
{#if $waitInProgress}
<Spinner size="sm" />
{:else}
<Icon name="skip-start-fill" />
{/if}
Effacer ma progression sur ce défi
</Button>
{/if}
</Col>
{/if}
</Row>
</Card>
{#if $my && $my.exercices[$current_exercice.id]}
<Row class="mt-4">
<Col lg="6" class="mb-5">
{#if $my.exercices[$current_exercice.id].files}
<ExerciceDownloads
files={$my.exercices[$current_exercice.id].files}
/>
{/if}
{#if $my.exercices[$current_exercice.id].hints}
<ExerciceHints
locked_theme={$current_theme.locked}
exercice={$my.exercices[$current_exercice.id]}
hints={$my.exercices[$current_exercice.id].hints}
/>
{/if}
</Col>
<Col lg="6" class="mb-5">
{#if $my.exercices[$current_exercice.id].flags && ($my.exercices[$current_exercice.id].non_found_flags > 0 || !$my.exercices[$current_exercice.id].solved_rank) && !solved[$current_exercice.id]}
{#if $current_theme.locked}
<Card class="border-danger mb-2">
<CardHeader class="bg-black text-light">
<Icon name="lock-fill" />
Faire son rapport
</CardHeader>
<CardBody>
<p>
Ce scénario n'est pas accessible&nbsp;!
</p>
<p>
Vous ne pouvez pas compléter son rapport.
</p>
</CardBody>
</Card>
{:else}
<ExerciceFlags
exercice={$my.exercices[$current_exercice.id]}
bind:forcesolved={solved[$current_exercice.id]}
flags={$my.exercices[$current_exercice.id].flags}
readonly={$current_exercice.disabled}
/>
{/if}
{/if}
{#if $my.exercices[$current_exercice.id].solved_rank || solved[$current_exercice.id]}
<ExerciceSolved
theme={$current_theme}
exercice={$my.exercices[$current_exercice.id]}
/>
{/if}
{#if $my.exercices[$current_exercice.id].resolution || $my.exercices[$current_exercice.id].video_uri}
<Card class="border-success mb-2">
<CardHeader class="bg-success text-light d-flex justify-content-between">
<div>
<Icon name="laptop-fill" />
Solution du défi
</div>
{#if $my.exercices[$current_exercice.id].resolution}
<Button color="success" size="sm" on:click={() => openResolution = true}>
<Icon name="arrows-angle-expand" />
</Button>
<ResolutionModal exercice={$current_exercice} bind:open={openResolution} resolution={$my.exercices[$current_exercice.id].resolution} />
{/if}
</CardHeader>
{#if $my.exercices[$current_exercice.id].resolution}
<CardBody>
{@html $my.exercices[$current_exercice.id].resolution}
</CardBody>
{/if}
{#if $my.exercices[$current_exercice.id].video_uri}
<ExerciceVideo uri={$my.exercices[$current_exercice.id].video_uri} />
{/if}
</Card>
{/if}
</Col>
</Row>
{/if}
{/if}