commit aa9c5c0fdd45c5545fbca0724aa86a61ea1fa4f3
parent f830a917479ddbdf09f94fd7dc5530f10737e9e7
Author: MTRNord <mtrnord1@gmail.com>
Date: Sat, 1 Jan 2022 20:40:33 +0100
Add basic login
Diffstat:
4 files changed, 197 insertions(+), 4 deletions(-)
diff --git a/components/Header.tsx b/components/Header.tsx
@@ -11,7 +11,7 @@ export default class Header extends Component {
<div className='flex grow-[1] h-full relative items-center'>
<form className='w-[200px] text-gray-900 dark:text-gray-200'>
<div className='flex flex-row box-border items-center cursor-text duration-300 rounded-sm border dark:border-slate-400 border-slate-500 py-1.5 px-2 focus-within:border-teal-400'>
- <input className='bg-transparent min-w-[20px] focus:outline-none flex-[1]' type="text" placeholder='Search & Discover' />
+ <input className='bg-transparent min-w-[20px] focus:outline-none flex-[1] border-none' type="text" placeholder='Search & Discover' />
<span className='inline-flex items-center justify-center cursor-pointer'>
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" className='fill-gray-900 dark:fill-gray-200'><path d="M0 0h24v24H0z" fill="none" /><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" /></svg>
</span>
diff --git a/helpers/matrix_client.ts b/helpers/matrix_client.ts
@@ -2,7 +2,7 @@
import { MatrixEvent } from './event_types';
import Storage from './storage';
-export const constMatrixArtServer = process.env.NEXT_PUBLIC_DEFAULT_SERVER_URL;
+export const constMatrixArtServer = process.env.NEXT_PUBLIC_DEFAULT_SERVER_URL as string;
export default class MatrixClient {
private joinedRooms: Map<any, any>;
@@ -112,6 +112,28 @@ export default class MatrixClient {
return data;
}
+ async login(serverUrl: string, username: any, password: any, saveToStorage: any) {
+ const data = await this.fetchJson(`${serverUrl}/r0/login`, {
+ method: "POST",
+ body: JSON.stringify({
+ type: "m.login.password",
+ identifier: {
+ type: "m.id.user",
+ user: username,
+ },
+ password: password,
+ }),
+ });
+ this.serverUrl = serverUrl;
+ this._userId = data.user_id;
+ this._accessToken = data.access_token;
+ this.isGuest = false;
+ this.serverName = data.home_server;
+ if (saveToStorage) {
+ this.saveAuthState();
+ }
+ }
+
async register(serverUrl: string, username: string, password: string) {
const data = await this.fetchJson(`${serverUrl}/r0/register`, {
method: "POST",
diff --git a/pages/Home.tsx b/pages/Home.tsx
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { RingLoader } from 'react-spinners';
-import { ImageEvent, ImageGalleryEvent, MatrixEventBase } from '../helpers/event_types';
+import { ImageEvent, ImageGalleryEvent, MatrixEventBase } from '../helpers/event_types';
import Link from 'next/link';
import Head from 'next/head';
import Header from '../components/Header';
@@ -22,7 +22,7 @@ type State = {
image_events: ImageEvents[] | [];
};
-const centerSpinner = `
+export const centerSpinner = `
position: fixed;
top: 50%;
left: 50%;
diff --git a/pages/login.tsx b/pages/login.tsx
@@ -0,0 +1,170 @@
+import Head from "next/head";
+import { NextRouter, withRouter } from "next/router";
+import { Component, ReactNode } from "react";
+import { RingLoader } from "react-spinners";
+import { ClientContext } from "../components/ClientContext";
+import Header from "../components/Header";
+import { constMatrixArtServer } from "../helpers/matrix_client";
+import { centerSpinner } from "./Home";
+
+type Props = {
+ router: NextRouter;
+};
+type State = {
+ showServerField: boolean;
+ serverUrl: string;
+ mxid?: string;
+ password?: string;
+ serverFieldsDisplay: string;
+ serverFieldsOpacity: number;
+ loading: boolean;
+};
+
+class Login extends Component<Props, State> {
+ declare context: React.ContextType<typeof ClientContext>;
+
+ constructor(props: Props | Readonly<Props>) {
+ super(props);
+ this.state = {
+ showServerField: false,
+ serverUrl: constMatrixArtServer + "/_matrix/client",
+ serverFieldsDisplay: 'none',
+ serverFieldsOpacity: 0,
+ loading: false,
+ } as State;
+
+ this.handleInputChange = this.handleInputChange.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ handleInputChange(event: { target: any; }) {
+ const target = event.target;
+ const value = target.type === 'checkbox' ? target.checked : target.value;
+ const name = target.name;
+ if (name == "showServerField") {
+ if (this.state.serverFieldsDisplay === 'none') {
+ this.setState({ serverFieldsDisplay: 'block' });
+ setTimeout(() =>
+ this.setState({ serverFieldsOpacity: 1 }), 10 // something very short
+ );
+ }
+ if (this.state.serverFieldsDisplay === 'block') {
+ this.setState({ serverFieldsOpacity: 0 });
+ setTimeout(() =>
+ this.setState({ serverFieldsDisplay: 'none' }), 400 // same as transition time
+ );
+ }
+ }
+ this.setState({
+ [name]: value
+ } as State);
+ }
+
+ async handleSubmit(event: { preventDefault: () => void; }) {
+ // TODO update client
+ event.preventDefault();
+ let serverUrl = this.state.serverUrl;
+ // Reset url if the field is hidden.
+ if (!this.state.showServerField) {
+ serverUrl = constMatrixArtServer + "/_matrix/client";
+ }
+
+ if (this.state.mxid && this.state.password) {
+ this.setState({
+ loading: true
+ });
+ await this.context.client.login(serverUrl, this.state.mxid, this.state.password, true);
+ this.props.router.replace("/");
+ }
+ }
+
+ render(): ReactNode {
+ const { loading } = this.state;
+ if (loading) {
+ return (
+ <>
+ <div className='h-full bg-[#f8f8f8] dark:bg-[#06070D]'>
+ <Head>
+ <title key="title">Matrix Art | Login</title>
+ <meta property="og:title" content="Matrix Art | Login" key="og-title" />
+ <meta property="og:type" content="website" key="og-type" />
+ </Head>
+ <Header></Header>
+ <main className="lg:pt-[108px] pt-[216px]">
+ <div className='z-[100] sticky lg:top-[108px] top-[216px] bg-[#fefefe]/[.95] dark:bg-[#14181E]/[.95]'>
+ <div className='h-[72px] px-10 w-full relative grid grid-cols-[1fr_auto_1fr] items-center' id='section-grid'>
+ <h1 className='text-xl text-gray-900 dark:text-gray-200 font-bold'>Log In</h1>
+ </div>
+ </div>
+ // TODO fix loader
+ </main>
+ </div>
+ </>
+ );
+ }
+ return (
+ <>
+ <div className='h-full bg-[#f8f8f8] dark:bg-[#06070D]'>
+ <Head>
+ <title key="title">Matrix Art | Login</title>
+ <meta property="og:title" content="Matrix Art | Login" key="og-title" />
+ <meta property="og:type" content="website" key="og-type" />
+ </Head>
+ <Header></Header>
+
+ <main className='lg:pt-[108px] pt-[216px]'>
+ <div className='z-[100] sticky lg:top-[108px] top-[216px] bg-[#fefefe]/[.95] dark:bg-[#14181E]/[.95]'>
+ <div className='h-[72px] px-10 w-full relative grid grid-cols-[1fr_auto_1fr] items-center' id='section-grid'>
+ <h1 className='text-xl text-gray-900 dark:text-gray-200 font-bold'>Log In</h1>
+ </div>
+ </div>
+ <div className="flex items-center justify-center m-10">
+ <form onSubmit={this.handleSubmit} className="grid grid-cols-1 gap-6">
+ <div className="block">
+ <div className="mt-2">
+ <div>
+ <label className="inline-flex items-center">
+ <input className="cursor-pointer h-[16px] w-[16px]" type="checkbox" name="showServerField" checked={this.state.showServerField} onChange={this.handleInputChange} />
+ <span className="ml-2 text-gray-900 dark:text-gray-200">Use custom Server</span>
+ </label>
+ </div>
+ </div>
+ </div>
+
+ <label style={{
+ transition: 'opacity 0.4s ease',
+ opacity: this.state.serverFieldsOpacity,
+ display: this.state.serverFieldsDisplay
+ }} id="homeserverField">
+ <span className="text-gray-900 dark:text-gray-200">Homeserver:</span>
+ <div className="mt-1 w-full flex flex-row box-border items-center cursor-text duration-300 rounded-sm border dark:border-slate-400 border-slate-500 py-1.5 px-2 focus-within:border-teal-400">
+ <input className="bg-transparent min-w-[20px] focus:outline-none flex-[1] border-none text-gray-900 dark:text-gray-200" type="text" name="serverUrl" value={this.state.serverUrl} onChange={this.handleInputChange} />
+ </div>
+ </label>
+
+ <label className="block">
+ <span className="text-gray-900 dark:text-gray-200">Username:</span>
+ <div className="mt-1 w-full flex flex-row box-border items-center cursor-text duration-300 rounded-sm border dark:border-slate-400 border-slate-500 py-1.5 px-2 focus-within:border-teal-400">
+ <input className="bg-transparent min-w-[20px] focus:outline-none flex-[1] border-none text-gray-900 dark:text-gray-200" type="text" name="mxid" value={this.state.mxid} onChange={this.handleInputChange} />
+ </div>
+ </label>
+ <label className="block">
+ <span className="text-gray-900 dark:text-gray-200">Password:</span>
+ <div className="mt-1 w-full flex flex-row box-border items-center cursor-text duration-300 rounded-sm border dark:border-slate-400 border-slate-500 py-1.5 px-2 focus-within:border-teal-400">
+ <input className="bg-transparent min-w-[20px] focus:outline-none flex-[1] border-none text-gray-900 dark:text-gray-200" type="password" name="password" value={this.state.password} onChange={this.handleInputChange} />
+ </div>
+ </label>
+
+
+ <input className="bg-teal-400 hover:bg-teal-500 cursor-pointer h-[42px] rounded dark:text-gray-900 text-gray-200" type="submit" value="Log In" />
+ </form>
+ </div>
+ </main>
+ </div>
+ </>
+ );
+ }
+}
+
+Login.contextType = ClientContext;
+export default withRouter(Login);
+\ No newline at end of file