mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-09 17:52:14 +00:00
Merge pull request #116 from EETagent/frontend_production
This commit is contained in:
commit
3d373c4daa
7 changed files with 65 additions and 15 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import axios, { type AxiosProgressEvent } from 'axios';
|
import axios, { type AxiosProgressEvent } from 'axios';
|
||||||
import type { CandidateData, CandidateLogin } from '$lib/stores/candidate';
|
import type { CandidateData, CandidateLogin, CreateCandidate } from '$lib/stores/candidate';
|
||||||
import type { SubmissionProgress } from '$lib/stores/portfolio';
|
import type { SubmissionProgress } from '$lib/stores/portfolio';
|
||||||
import { API_URL, errorHandler, type Fetch } from '.';
|
import { API_URL, errorHandler, type Fetch } from '.';
|
||||||
import DOMPurify from 'isomorphic-dompurify';
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
@ -12,7 +12,6 @@ export const apiLogout = async (fetchSsr?: Fetch) => {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include'
|
credentials: 'include'
|
||||||
});
|
});
|
||||||
return await res.json();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw errorHandler(e, 'Logout failed');
|
throw errorHandler(e, 'Logout failed');
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +51,7 @@ export const apiFetchSubmissionProgress = async (fetchSsr?: Fetch): Promise<Subm
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apiWhoami = async (fetchSsr?: Fetch): Promise<string> => {
|
export const apiWhoami = async (fetchSsr?: Fetch): Promise<CreateCandidate> => {
|
||||||
const apiFetch = fetchSsr || fetch;
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
console.log(API_URL + '/candidate/whoami');
|
console.log(API_URL + '/candidate/whoami');
|
||||||
|
|
@ -63,7 +62,7 @@ export const apiWhoami = async (fetchSsr?: Fetch): Promise<string> => {
|
||||||
if (res.status != 200) {
|
if (res.status != 200) {
|
||||||
throw Error(await res.text());
|
throw Error(await res.text());
|
||||||
}
|
}
|
||||||
return await res.text();
|
return await res.json();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw errorHandler(e, 'Failed to fetch whoami');
|
throw errorHandler(e, 'Failed to fetch whoami');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import debounce from 'just-debounce-it';
|
import debounce from 'just-debounce-it';
|
||||||
|
|
||||||
import { apiDeltePortfolio, apiGetPortfolio, apiSubmitPortfolio } from '$lib/@api/candidate';
|
import { apiDeltePortfolio, apiGetPortfolio, apiLogout, apiSubmitPortfolio } from '$lib/@api/candidate';
|
||||||
import Circles from '$lib/components/icons/Circles.svelte';
|
import Circles from '$lib/components/icons/Circles.svelte';
|
||||||
import { fetchSubmProgress, type Status } from '$lib/stores/portfolio';
|
import { fetchSubmProgress, type Status } from '$lib/stores/portfolio';
|
||||||
import StatusNotificationBig from './StatusNotificationBig.svelte';
|
import StatusNotificationBig from './StatusNotificationBig.svelte';
|
||||||
import InfoButton from './InfoButton.svelte';
|
import InfoButton from './InfoButton.svelte';
|
||||||
import { candidateData } from '$lib/stores/candidate';
|
import { baseCandidateData, candidateData } from '$lib/stores/candidate';
|
||||||
import tippy, {sticky} from 'tippy.js';
|
import tippy, {sticky} from 'tippy.js';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
|
|
@ -63,18 +63,24 @@
|
||||||
const editDetails = async () => {
|
const editDetails = async () => {
|
||||||
goto('/register?edit=true')
|
goto('/register?edit=true')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logout = async () => {
|
||||||
|
await apiLogout();
|
||||||
|
goto("/auth/login");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card flex flex-col">
|
<div class="card flex flex-col">
|
||||||
<div class="infoBar <2xl:flex-col flex flex-row-reverse">
|
<div class="infoBar <2xl:flex-col flex flex-row-reverse">
|
||||||
<StatusNotificationBig {loading} {status} on:click={debounce(handleNotificationClick, 150)} />
|
<StatusNotificationBig {loading} {status} on:click={debounce(handleNotificationClick, 150)} />
|
||||||
<div class="mr-4">
|
<div class="mr-4 <2xl:mr-1">
|
||||||
<div on:click on:keydown class="flex flex-col">
|
<div on:click on:keydown class="flex flex-col">
|
||||||
<div class="<2xl:ml-auto <2xl:flex-row <2xl:my-2 flex flex-col">
|
<div class="<2xl:ml-auto <2xl:flex-row <2xl:my-2 flex flex-col">
|
||||||
<InfoButton
|
<InfoButton
|
||||||
bind:showDetails
|
bind:showDetails
|
||||||
on:download={downloadPortfolio}
|
on:download={downloadPortfolio}
|
||||||
on:showInfo={(_) => (showDetails = !showDetails)}
|
on:showInfo={(_) => (showDetails = !showDetails)}
|
||||||
|
on:logout={logout}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -82,11 +88,23 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="relative my-2 flex flex-col overflow-hidden">
|
<div class="relative my-2 flex flex-col overflow-hidden">
|
||||||
<div>
|
<div>
|
||||||
<span class="absolute -left-16 -top-36">
|
|
||||||
<Circles />
|
|
||||||
</span>
|
|
||||||
<div class="mt-[5%] flex flex-col">
|
<div class="mt-[5%] flex flex-col">
|
||||||
<h3>{title}</h3>
|
<div class="flex justify-between">
|
||||||
|
<h3>{title}</h3>
|
||||||
|
<span
|
||||||
|
on:click={logout}
|
||||||
|
on:keydown={logout}
|
||||||
|
use:tippy={{
|
||||||
|
content: 'Odhlásit se',
|
||||||
|
placement: 'top',
|
||||||
|
showOnCreate: false,
|
||||||
|
sticky: true,
|
||||||
|
plugins: [sticky]
|
||||||
|
}}
|
||||||
|
class="<2xl:hidden hover:cursor-pointer">
|
||||||
|
<svg class="w-10 h-10 stroke-sspsBlueDark" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path></svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -103,6 +121,8 @@
|
||||||
}}
|
}}
|
||||||
class="mt-4 flex flex-col justify-between leading-10"
|
class="mt-4 flex flex-col justify-between leading-10"
|
||||||
>
|
>
|
||||||
|
<span>Ev. č. přihlášky: <span class="font-bold">{$baseCandidateData.applicationId}</span></span>
|
||||||
|
<span>Obor: <span class="font-bold">{$candidateData.candidate.study}</span></span>
|
||||||
<span>Adresa: <span class="font-bold">{$candidateData.candidate.address}</span></span>
|
<span>Adresa: <span class="font-bold">{$candidateData.candidate.address}</span></span>
|
||||||
<span
|
<span
|
||||||
>Datum narození: <span class="font-bold">{$candidateData.candidate.birthdate}</span
|
>Datum narození: <span class="font-bold">{$candidateData.candidate.birthdate}</span
|
||||||
|
|
@ -162,7 +182,7 @@
|
||||||
|
|
||||||
@apply bg-[#f8fbfc];
|
@apply bg-[#f8fbfc];
|
||||||
@apply rounded-3xl;
|
@apply rounded-3xl;
|
||||||
@apply px-7 py-10;
|
@apply px-7 py-10 <2xl:px-5 <2xl:py-5;
|
||||||
|
|
||||||
@apply transition-all duration-300;
|
@apply transition-all duration-300;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import { submissionProgress, UploadStatus } from '$lib/stores/portfolio';
|
import { submissionProgress, UploadStatus } from '$lib/stores/portfolio';
|
||||||
import Document from '../icons/Document.svelte';
|
import Document from '../icons/Document.svelte';
|
||||||
import Download from '../icons/Download.svelte';
|
import Download from '../icons/Download.svelte';
|
||||||
|
import { sticky } from 'tippy.js';
|
||||||
|
|
||||||
export let showDetails: boolean;
|
export let showDetails: boolean;
|
||||||
|
|
||||||
|
|
@ -17,6 +18,10 @@
|
||||||
const download = () => {
|
const download = () => {
|
||||||
dispatch('download');
|
dispatch('download');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
dispatch('logout');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
|
|
@ -73,11 +78,28 @@
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<span
|
||||||
|
use:tippy={{
|
||||||
|
content: 'Odhlásit se',
|
||||||
|
placement: 'top',
|
||||||
|
showOnCreate: false,
|
||||||
|
sticky: true,
|
||||||
|
plugins: [sticky]
|
||||||
|
}}
|
||||||
|
on:click={(_) => logout()}
|
||||||
|
on:keydown={(_) => logout()}
|
||||||
|
class="icon logoutIcon ml-1 hover:cursor-pointer">
|
||||||
|
<svg class="w-10 h-10 icon logoutIcon" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path></svg>
|
||||||
|
</span>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.icon {
|
.icon {
|
||||||
@apply text-sspsBlueDark h-10 w-10 transition-colors duration-300 hover:cursor-pointer;
|
@apply text-sspsBlueDark h-10 w-10 transition-colors duration-300 hover:cursor-pointer;
|
||||||
@apply hover:text-sspsBlue;
|
@apply hover:text-sspsBlue;
|
||||||
}
|
}
|
||||||
|
.logoutIcon {
|
||||||
|
@apply 2xl:hidden;
|
||||||
|
}
|
||||||
.showDetails {
|
.showDetails {
|
||||||
@apply text-sspsBlue;
|
@apply text-sspsBlue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.info {
|
.info {
|
||||||
@apply flex items-center justify-between;
|
@apply flex items-center justify-between;
|
||||||
@apply py-3 px-6;
|
@apply py-3 px-3;
|
||||||
@apply rounded-xl border-red-700 bg-red-700 shadow-md;
|
@apply rounded-xl border-red-700 bg-red-700 shadow-md;
|
||||||
|
|
||||||
@apply hover:cursor-help;
|
@apply hover:cursor-help;
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@ export interface CreateCandidateLogin extends CreateCandidate {
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const baseCandidateData= writable<CreateCandidate>({
|
||||||
|
applicationId: 0,
|
||||||
|
personalIdNumber: ''
|
||||||
|
});
|
||||||
|
|
||||||
export const candidateData = writable<CandidateData>({
|
export const candidateData = writable<CandidateData>({
|
||||||
candidate: {
|
candidate: {
|
||||||
name: '',
|
name: '',
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,12 @@ export const load: LayoutServerLoad = async ({ cookies, fetch }) => {
|
||||||
const isAuthenticated = cookies.get('id');
|
const isAuthenticated = cookies.get('id');
|
||||||
|
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
await apiWhoami(fetch).catch((e) => {
|
const whoami = await apiWhoami(fetch).catch((e) => {
|
||||||
throw redirect(302, '/auth/logout');
|
throw redirect(302, '/auth/logout');
|
||||||
});
|
});
|
||||||
|
return {
|
||||||
|
whoami: whoami
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw redirect(302, '/auth/logout');
|
throw redirect(302, '/auth/logout');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
UploadStatus,
|
UploadStatus,
|
||||||
type Status
|
type Status
|
||||||
} from '$lib/stores/portfolio';
|
} from '$lib/stores/portfolio';
|
||||||
import { candidateData } from '$lib/stores/candidate';
|
import { baseCandidateData, candidateData } from '$lib/stores/candidate';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
$: candidateData.set(data.candidate);
|
$: candidateData.set(data.candidate);
|
||||||
$: submissionProgress.set(data.submission);
|
$: submissionProgress.set(data.submission);
|
||||||
|
$: baseCandidateData.set(data.whoami);
|
||||||
|
|
||||||
const getUploadStatus = (progressStatus: UploadStatus | undefined): Status => {
|
const getUploadStatus = (progressStatus: UploadStatus | undefined): Status => {
|
||||||
switch (progressStatus) {
|
switch (progressStatus) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue