mirror of
https://github.com/psforever/PSFPortal.git
synced 2026-07-12 06:55:07 +00:00
Enable foreign profile view
This commit is contained in:
parent
20946fdb43
commit
cb918033a6
14 changed files with 248 additions and 125 deletions
|
|
@ -14,11 +14,10 @@
|
|||
import { onMount } from 'svelte';
|
||||
import page from 'page';
|
||||
|
||||
import { fade } from 'svelte/transition';
|
||||
import { get_initial_state } from './UserState.js';
|
||||
|
||||
import Nav from './components/Nav.svelte'
|
||||
import Alert from './components/Alert.svelte'
|
||||
|
||||
import Home from './views/Home.svelte';
|
||||
import Login from './views/Login.svelte';
|
||||
import Register from './views/Register.svelte';
|
||||
|
|
@ -28,12 +27,12 @@ import UserList from './views/UserList.svelte';
|
|||
import AdminPanel from './views/AdminPanel.svelte';
|
||||
import CharacterList from './views/CharacterList.svelte';
|
||||
|
||||
// prevent pop-in
|
||||
// prevent view pop-in
|
||||
let initialized = false;
|
||||
|
||||
onMount(async () => {
|
||||
await get_initial_state()
|
||||
initialized = true;
|
||||
page() // start the router
|
||||
});
|
||||
|
||||
let route;
|
||||
|
|
@ -53,9 +52,18 @@ function setRoute(r, initialState) {
|
|||
if (!first)
|
||||
previousCtx = currentCtx
|
||||
|
||||
if (!first && currentCtx.route == r)
|
||||
if (!first && ctx.pathname == previousCtx.pageCtx.pathname)
|
||||
return
|
||||
|
||||
if (process.env.NODE_ENV !== "production" && !first) {
|
||||
console.log("-------------------NEW ROUTE--------------\n",
|
||||
previousCtx.pageCtx.pathname, " -> ", ctx.pathname)
|
||||
|
||||
if (previousCtx && r == previousCtx.route)
|
||||
console.log("/!\\ Re-rendering same view with different params")
|
||||
}
|
||||
|
||||
// We are changing views, clear the global app message
|
||||
if (appAlert)
|
||||
appAlert.message("");
|
||||
|
||||
|
|
@ -64,27 +72,39 @@ function setRoute(r, initialState) {
|
|||
else
|
||||
initialized = true;
|
||||
|
||||
// Change the component context
|
||||
currentCtx = {
|
||||
route : r,
|
||||
routeParams : ctx.params,
|
||||
pageCtx : ctx,
|
||||
}
|
||||
|
||||
/* If the previous view compoent was the same, we need to
|
||||
force svelte to rerender it if some of the parameters have changed.
|
||||
For example, clicking from another User's view to ourself wont lead
|
||||
to a render due to the component not changing. We force this change
|
||||
by scheduling the two changes on separate ticks.
|
||||
*/
|
||||
if (previousCtx && r == previousCtx.route) {
|
||||
setImmediate(() => currentCtx.route = null)
|
||||
setImmediate(() => currentCtx.route = r)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
page("/", setRoute(Home, true));
|
||||
page("/login", setRoute(Login, true));
|
||||
page("/register", setRoute(Register));
|
||||
page("/register", setRoute(Register));
|
||||
page("/admin", setRoute(AdminPanel));
|
||||
page("/profile", setRoute(Profile, true));
|
||||
page("/user/:id", setRoute(Profile, true));
|
||||
//page("/users", setRoute(UserList));
|
||||
//page("/characters", setRoute(CharacterList));
|
||||
page("/admin", setRoute(AdminPanel));
|
||||
//page("/recovery", setRoute(Recovery));
|
||||
page("/profile", setRoute(Profile, true));
|
||||
page("*", setRoute(BadRoute));
|
||||
page()
|
||||
</script>
|
||||
|
||||
{#if currentCtx}
|
||||
<Nav bind:route={currentCtx.pageCtx.pathname}/>
|
||||
|
||||
<main role="main" class="container">
|
||||
|
|
@ -104,3 +124,4 @@ All other trademarks or tradenames are properties of their respective owners.
|
|||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,11 @@ export async function logout() {
|
|||
page("/")
|
||||
}
|
||||
|
||||
loggedIn.subscribe((v) => {
|
||||
console.log(loggedIn, v)
|
||||
})
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
loggedIn.subscribe((v) => {
|
||||
console.log("Login state: ", v)
|
||||
})
|
||||
}
|
||||
|
||||
export async function get_initial_state() {
|
||||
try {
|
||||
|
|
@ -42,7 +44,6 @@ export async function get_initial_state() {
|
|||
if (e.response.status === 403) {
|
||||
console.log("User not logged in / not admin!")
|
||||
clear_user_state();
|
||||
return false;
|
||||
} else {
|
||||
console.log("Unknown login error", e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
{/if}
|
||||
|
||||
{#if $isAdmin}
|
||||
<a href="/character/{character.id}">{character.name}</a>
|
||||
<a href="/user/{character.account_id}">{character.name}</a>
|
||||
{:else}
|
||||
<span>{character.name}</span>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { cubicOut } from 'svelte/easing';
|
||||
|
||||
const progress = tweened(0, {
|
||||
delay: 100,
|
||||
duration: 1000,
|
||||
easing: cubicOut
|
||||
});
|
||||
|
|
@ -16,21 +17,22 @@
|
|||
let tr, nc, vs;
|
||||
|
||||
onMount(() => {
|
||||
setTimeout(() => progress.set(1.0), 100);
|
||||
|
||||
tr.style.height = "1px";
|
||||
nc.style.height = "1px";
|
||||
vs.style.height = "1px";
|
||||
|
||||
progress.subscribe((v) => {
|
||||
if (!tr || !nc || !vs)
|
||||
return;
|
||||
|
||||
tr.style.height = v*percentages.TR*200 + "px";
|
||||
nc.style.height = v*percentages.NC*200 + "px";
|
||||
vs.style.height = v*percentages.VS*200 + "px";
|
||||
})
|
||||
|
||||
setTimeout(() => progress.set(1.0), 100);
|
||||
})
|
||||
|
||||
progress.subscribe((v) => {
|
||||
if (tr === undefined || !tr.style)
|
||||
return
|
||||
|
||||
tr.style.height = v*percentages.TR*200 + "px";
|
||||
nc.style.height = v*percentages.NC*200 + "px";
|
||||
vs.style.height = v*percentages.VS*200 + "px";
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
|
|||
|
|
@ -21,15 +21,26 @@
|
|||
</script>
|
||||
|
||||
<PaginatedList {fetch} let:data={logins} let:pagination={pagination}>
|
||||
<p slot="header">
|
||||
{#if pagination.item_count}
|
||||
Login data
|
||||
{:else}
|
||||
No logins yet
|
||||
{/if}
|
||||
</p>
|
||||
<table slot="body" class="table table-dark table-responsive">
|
||||
<thead>
|
||||
<td>Login Time</td>
|
||||
<td>From</td>
|
||||
<td>Login Date</td>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{#each logins as login, i}
|
||||
<tr>
|
||||
<td>{moment(login.login_time).fromNow()}</td>
|
||||
<td>
|
||||
<code>{login.hostname} - {login.ip_address}</code>
|
||||
</td>
|
||||
<td>{moment(login.login_time).format('MMMM Do YYYY, h:mm:ss a')} ({moment(login.login_time).fromNow()})</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
import { get_initial_state, logout, isAdmin, loggedIn, username } from '../UserState.js';
|
||||
import axios from 'axios'
|
||||
export let route;
|
||||
export let pageCtx;
|
||||
console.log(pageCtx)
|
||||
</script>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark justify-content-between">
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import axios from 'axios'
|
||||
import Pagination from '../components/Pagination'
|
||||
|
||||
export let setURLParam = false;
|
||||
export let fetch;
|
||||
|
||||
let data;
|
||||
|
|
@ -15,12 +16,16 @@
|
|||
|
||||
onMount(async () => {
|
||||
const url = new URL(window.location.href)
|
||||
let page = url.searchParams.get('page')
|
||||
let initialPage = 1;
|
||||
|
||||
if (page == undefined)
|
||||
page = 1;
|
||||
if (setURLParam) {
|
||||
let param = parseInt(url.searchParams.get('page'))
|
||||
|
||||
await list_fetch(page);
|
||||
if (param != NaN)
|
||||
initialPage = param;
|
||||
}
|
||||
|
||||
await list_fetch(initialPage);
|
||||
})
|
||||
|
||||
async function pageChange(page) {
|
||||
|
|
@ -50,8 +55,10 @@
|
|||
|
||||
{#if data}
|
||||
<slot name="header" data={data} pagination={pagination}></slot>
|
||||
<Pagination {pagination} {pageChange} />
|
||||
{#if pagination.item_count > 0}
|
||||
<Pagination {pagination} {pageChange} {setURLParam} />
|
||||
<slot name="body" data={data} pagination={pagination}></slot>
|
||||
<Pagination {pagination} {pageChange} />
|
||||
<Pagination {pagination} {pageChange} {setURLParam} />
|
||||
{/if}
|
||||
<slot name="footer" data={data} pagination={pagination}></slot>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,31 @@
|
|||
<script>
|
||||
export let pagination;
|
||||
export let pageChange;
|
||||
let numPages = 10;
|
||||
export let setURLParam = false;
|
||||
export let displayPages = 10;
|
||||
|
||||
let pages = []
|
||||
|
||||
function pageClick(event) {
|
||||
const page = event.target.getAttribute('data-page');
|
||||
pageChange(parseInt(page))
|
||||
|
||||
if (!setURLParam)
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
$ : {
|
||||
const new_pages = [];
|
||||
let pi = 0, i;
|
||||
let pg = pagination;
|
||||
|
||||
const pageChunk = Math.max(Math.ceil(numPages/3), 1);
|
||||
const pageChunk = Math.max(Math.ceil(displayPages/3), 1);
|
||||
const middleChunk = Math.max(Math.ceil(pageChunk/2), 1);
|
||||
const leftBound = Math.min(pageChunk+1, pagination.page_count);
|
||||
const rightBound = Math.max(pagination.page_count-pageChunk, 1);
|
||||
|
||||
// fast path: draw all pages
|
||||
if (pg.page_count <= numPages || rightBound <= leftBound) {
|
||||
if (pg.page_count <= displayPages || rightBound <= leftBound) {
|
||||
for (i = 1; i <= pg.page_count; i++)
|
||||
new_pages[pi++] = i;
|
||||
} else {
|
||||
|
|
@ -54,27 +64,31 @@
|
|||
<p>Displaying {(pagination.page-1)*pagination.items_per_page+1} — {Math.min(pagination.page*pagination.items_per_page, pagination.item_count)}</p>
|
||||
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm">
|
||||
<li class="page-item" class:disabled={pagination.page<=1}>
|
||||
<a class="page-link" href={"?page="+(pagination.page-1)}
|
||||
on:click={(e) => pageChange(pagination.page-1)}
|
||||
aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{#each pages as page,i}
|
||||
<ul class="pagination pagination-sm">
|
||||
<li class="page-item" class:disabled={pagination.page<=1}>
|
||||
<a class="page-link" href={"?page="+(pagination.page-1)}
|
||||
on:click={pageClick}
|
||||
data-page={pagination.page-1}
|
||||
aria-label="Previous">
|
||||
«
|
||||
</a>
|
||||
</li>
|
||||
{#each pages as page,i}
|
||||
{#if page == -1}
|
||||
<li class="page-item page-last-separator disabled" ><a class="page-link">...<a></li>
|
||||
<li class="page-item page-last-separator disabled"><span class="page-link">...</span></li>
|
||||
{:else}
|
||||
<li class="page-item" class:active={page==pagination.page}><a on:click={(e) => pageChange(page)} href={"?page="+page} class="page-link">{page}</a></li>
|
||||
<li class="page-item" class:active={page==pagination.page}>
|
||||
<a on:click={pageClick} href={"?page="+page} data-page={page} class="page-link">{page}</a>
|
||||
</li>
|
||||
{/if}
|
||||
{/each}
|
||||
<li class="page-item" class:disabled={pagination.page>=pagination.page_count}>
|
||||
<a class="page-link" href={"?page="+(pagination.page+1)}
|
||||
on:click={(e) => pageChange(pagination.page+1)}
|
||||
aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{/each}
|
||||
<li class="page-item" class:disabled={pagination.page>=pagination.page_count}>
|
||||
<a class="page-link" href={"?page="+(pagination.page+1)}
|
||||
data-page={pagination.page+1}
|
||||
on:click={pageClick}
|
||||
aria-label="Next">
|
||||
»
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,15 @@
|
|||
import page from 'page'
|
||||
import moment from 'moment'
|
||||
import CharacterLink from '../components/CharacterLink'
|
||||
import { userId } from '../UserState'
|
||||
import LoginList from '../components/LoginList'
|
||||
import AccountLink from '../components/AccountLink'
|
||||
|
||||
export let pageCtx;
|
||||
export let appAlert;
|
||||
export let params;
|
||||
export let ready;
|
||||
|
||||
ready = false;
|
||||
|
||||
let username;
|
||||
|
|
@ -17,8 +23,10 @@
|
|||
let account;
|
||||
|
||||
onMount(async () => {
|
||||
let loadID = params.id || $userId;
|
||||
|
||||
try {
|
||||
const resp = await axios.get("/api/user/profile")
|
||||
const resp = await axios.get("/api/user/"+loadID+"/profile")
|
||||
account = resp.data;
|
||||
username = resp.data.name;
|
||||
characters = resp.data.characters;
|
||||
|
|
@ -30,7 +38,13 @@
|
|||
ready = true
|
||||
} catch (e) {
|
||||
if (e.response && e.response.status == 403) {
|
||||
page("/login?redirect=/profile")
|
||||
if (e.response.data.message == "session required") {
|
||||
page("/login?redirect="+pageCtx.pathname)
|
||||
} else {
|
||||
appAlert.message(e.response.data.message)
|
||||
}
|
||||
} else {
|
||||
appAlert.message(e.message)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -40,17 +54,9 @@
|
|||
<title>PSForever - Profile</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Your Account</h1>
|
||||
{#if account}
|
||||
<h1>Account: <AccountLink account={account}/></h1>
|
||||
<form>
|
||||
{#if isAdmin}
|
||||
<strong class="color-red">You are a GM.</strong>
|
||||
{/if}
|
||||
<div class="form-group row">
|
||||
<label for="staticUsername" class="col-sm-2 col-form-label">Username</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" readonly class="form-control-plaintext" id="staticUsername" bind:value={username}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="staticEmail" class="col-sm-2 col-form-label">Email</label>
|
||||
<div class="col-sm-10">
|
||||
|
|
@ -66,17 +72,21 @@
|
|||
</form>
|
||||
|
||||
<h2>Characters</h2>
|
||||
{#if characters.length > 1}
|
||||
<div class="row">
|
||||
{#each characters as char, i}
|
||||
<div class="col-md-4 col-12"><CharacterLink character={char} /></div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<p>You have no characters</p>
|
||||
{/if}
|
||||
<p>
|
||||
{#if characters.length > 1}
|
||||
<div class="row">
|
||||
{#each characters as char, i}
|
||||
<div class="col-md-4 col-12"><CharacterLink character={char} /></div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
You have no characters
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
<h2>Logins</h2>
|
||||
{#if account}
|
||||
<p>
|
||||
<LoginList account_id={account.id} />
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue