Add Rails backend: accounts via magic link, server documents, sharing
The app becomes a Rails 8 application; the Vue frontend moves to app/frontend and is served through vite_rails. - Without an account documents stay in the browser (IndexedDB). Sign-in is by magic link or the 6-digit code from the same mail; afterwards local documents can be uploaded into the account. - Server documents (/d/<id>) with versioned saves and a single-editor lock per browser tab; others see them read-only and follow by polling. - Sharing via link (works without an account) and via e-mail invitation, roles viewer/editor; the owner manages links and people. - Store gains a read-only mode that blocks all content changes. - Solid Queue, Cache and Cable share the one PostgreSQL database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Who is signed in. An account is optional: without one, documents stay in
|
||||
* this browser (IndexedDB); with one, they live on the server and can be
|
||||
* shared. Sign-in is by magic link or the 6-digit code from the same mail.
|
||||
*/
|
||||
import { computed, reactive } from 'vue';
|
||||
import { api, bootData, type User } from '../io/api';
|
||||
|
||||
const state = reactive({ user: bootData().user as User | null });
|
||||
|
||||
export function useSession() {
|
||||
const signedIn = computed(() => !!state.user);
|
||||
|
||||
/** Mail a sign-in link + code. `returnTo` = where the link leads back to. */
|
||||
async function requestLink(email: string, returnTo = location.pathname + location.search) {
|
||||
await api('POST', '/auth/magic_link', { body: { email, return_to: returnTo } });
|
||||
}
|
||||
|
||||
/** Sign in with the code. The page reloads, so everything starts signed in. */
|
||||
async function verifyCode(email: string, code: string) {
|
||||
await api<{ redirect: string }>('POST', '/auth/code', { body: { email, code } });
|
||||
location.reload();
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
await api('DELETE', '/auth/session');
|
||||
location.assign('/');
|
||||
}
|
||||
|
||||
async function setDisplayName(display_name: string) {
|
||||
const r = await api<{ user: User }>('PATCH', '/me', { body: { display_name } });
|
||||
state.user = r.user;
|
||||
}
|
||||
|
||||
return { state, signedIn, requestLink, verifyCode, logout, setDisplayName };
|
||||
}
|
||||
Reference in New Issue
Block a user