cleanup, api, databuddy

This commit is contained in:
Elijah Lucian 2021-04-14 18:03:23 -06:00
parent a8869e5fdd
commit 8df1fed14c
12 changed files with 30813 additions and 9005 deletions

20202
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@dank-inc/data-buddy": "^0.1.4",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",

View File

@ -1,27 +1,53 @@
import { message } from 'antd'
import axios from 'axios'
import Axios, { AxiosInstance } from 'axios'
import { User } from '../types'
import { mockUser } from './data'
import { JWT, getJWT, setHeaders, setJWT, wipeJWT } from '../utils/jwt'
import { JWT, setJWT, wipeJWT } from '../utils/jwt'
import { DataBuddy } from '@dank-inc/data-buddy'
const dev = process.env.NODE_ENV === 'development'
export type ApiParams = {
baseURL?: string
mock?: boolean
users: DataBuddy<User>
}
export const logIn = async (username: string, password: string) => {
// if (dev) return mockUser
export interface Api {
mock?: boolean
users: DataBuddy<User>
axios: AxiosInstance
}
try {
const { data: jwt } = await axios.post<JWT>(`/api/dj-rest-auth/login/`, {
export class Api {
constructor({ mock, users, baseURL }: ApiParams) {
this.mock = mock
this.users = users
this.axios = Axios.create({ baseURL })
}
login = async (username: string, password: string): Promise<JWT> => {
if (this.mock)
return {
id: 'mock-id',
token: 'token-token-token',
exp: +new Date(),
}
const { data } = await this.axios.post<JWT>(`/api/dj-rest-auth/login/`, {
username,
password,
})
setJWT(jwt)
setJWT(data)
return data
}
const user = await getLoggedInUser()
return user
} catch (err) {
console.log(err)
message.error('Error logging in!')
logout = () => {
if (this.mock) return true
wipeJWT()
}
getUser = async (id: string) => {
if (this.mock) return this.users.getOne(id)
const { data } = await this.axios.get<User>(`users/${id}`)
return data
}
}
@ -29,13 +55,3 @@ export const logOut = () => {
wipeJWT()
// axios -> delete session?
}
export const getLoggedInUser = async () => {
if (dev) return mockUser
const jwt = getJWT()
if (!jwt) throw new Error('User not logged in') // TODO: decorator
const { data } = await axios.get<User>(`/users/${jwt.id}`, setHeaders())
return data
}

View File

@ -3,20 +3,14 @@ import { useUserContext } from '../contexts/UserContext'
import { Login } from './pages/Login'
import { Route, Switch } from 'react-router'
import { Dashboard } from './pages/Dashboard'
import { NavRoute, AppHeader } from './layout/AppHeader'
import { AppHeader } from './layout/AppHeader'
import { Profile } from './pages/Profile'
import { NewUser } from './forms/NewUser'
import { ForgotPassword } from './pages/ForgotPassword'
export const CoreLayout = () => {
const { user } = useUserContext()
const routes: NavRoute[] = [
{ exact: true, path: '/', label: 'Dashboard', component: Dashboard },
{ path: '/profile', label: 'Profile', component: Profile },
{ path: '/login', label: 'Login', component: Login },
{ path: '/new/user', label: 'New User', component: NewUser },
]
if (!user)
return (
<Layout className="layout">
@ -28,14 +22,16 @@ export const CoreLayout = () => {
// header, sidebar, avatar?
return (
<Layout className="layout">
<AppHeader user={user} routes={routes} />
<Switch>
<AppHeader user={user} />
<Layout.Content>
{routes.map(({ exact, path, component }) => (
<Route exact={exact} key={path} path={path} component={component} />
))}
</Layout.Content>
<Switch>
<Route path="/forgot-password" component={ForgotPassword} />
<Route path="/login" component={Login} />
<Route path="/new/user" component={NewUser} />
<Route path="/profile" component={Profile} />
<Route exact path="/" component={Dashboard} />
</Switch>
</Layout.Content>
</Layout>
)
}

View File

@ -1,8 +1,8 @@
import React from 'react'
import { Avatar, Button, Typography } from 'antd'
import { Avatar, Button, Dropdown, Menu } from 'antd'
import { Header } from 'antd/lib/layout/layout'
import { User } from '../../types'
import { Link, useHistory } from 'react-router-dom'
import { useUserContext } from '../../contexts/UserContext'
export type NavRoute = {
path: string
@ -13,16 +13,16 @@ export type NavRoute = {
type Props = {
user: User | null
routes?: NavRoute[]
}
export const AppHeader = ({ user, routes }: Props) => {
export const AppHeader = ({ user }: Props) => {
const { handleLogout } = useUserContext()
const history = useHistory()
// Unauthed Header
if (!user)
return (
<Header className="app-header">
<Typography.Title level={3}>MVP Django React! 🤠</Typography.Title>
<h3>MVP Django React! 🤠</h3>
</Header>
)
@ -30,19 +30,29 @@ export const AppHeader = ({ user, routes }: Props) => {
return (
<Header className="app-header">
<div className="header-left">
<Typography.Title level={3}>MVP Django React! 🤠</Typography.Title>
{routes?.map((route) => (
<Link key={`${route.path}-${route.label}`} to={route.path}>
{route.label}
<Link to="/">
<h1>MVP Django React! 🤠</h1>
</Link>
))}
</div>
<div>
<Button onClick={() => history.push('/new/user')}>New User</Button>
</div>
<div className="header-right">
<Typography.Paragraph>Welcome, {user.username}!!</Typography.Paragraph>
<p>Welcome, {user.username}!!</p>
<Dropdown
overlay={
<Menu style={{ display: 'flex', flexDirection: 'column' }}>
<Button onClick={() => history.push('/login')}>Login</Button>
<Button onClick={handleLogout}>Logout</Button>
<Button onClick={() => history.push('/forgot-password')}>
Forgot Password
</Button>
<Button onClick={() => history.push('/profile')}>Profile</Button>
</Menu>
}
>
<Avatar>{user.username[0]}</Avatar>
</Dropdown>
</div>
</Header>
)

View File

@ -0,0 +1,22 @@
import { Button, Input, Layout } from 'antd'
import { useState } from 'react'
export const ForgotPassword = () => {
const [email, setEmail] = useState('')
const handleClick = () => {
console.log(email)
}
return (
<Layout>
<h1>Forgot Password</h1>
<Input
value={email}
onChange={(e) => setEmail(e.target.value)}
type="email"
/>
<Button onClick={handleClick}>Submit</Button>
</Layout>
)
}

File diff suppressed because it is too large Load Diff

13
node_modules/.package-lock.json generated vendored Normal file
View File

@ -0,0 +1,13 @@
{
"name": "mvp-django-react",
"lockfileVersion": 2,
"requires": true,
"packages": {
"node_modules/@dank-inc/data-buddy": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@dank-inc/data-buddy/-/data-buddy-0.1.3.tgz",
"integrity": "sha512-GreH0gs1Wf/8thCt53FrzX0ngMuIhrTBZJWa6tlqLIST4EgKgJN6IPei1o7bOqKPFmLIMS/DG6o1b/QAC57oXw==",
"license": "MIT"
}
}
}

7
node_modules/@dank-inc/data-buddy/README.md generated vendored Normal file
View File

@ -0,0 +1,7 @@
# Data Buddy
Need a little mock data thingy?
# Look no further!
I will document this someday

13
node_modules/@dank-inc/data-buddy/lib/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,13 @@
declare type DataRecord = {
id: string;
};
export declare type DataBuddyParams<T extends DataRecord> = T[];
export declare class DataBuddy<T extends DataRecord> {
data: T[];
constructor(records: T[]);
get: () => T[];
getOne: (id: string) => T | null;
update: (id: string, params: Partial<T>) => T | false;
delete: (id: string) => boolean;
}
export {};

43
node_modules/@dank-inc/data-buddy/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,43 @@
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataBuddy = void 0;
var DataBuddy = (function () {
function DataBuddy(records) {
var _this = this;
this.get = function () {
return _this.data;
};
this.getOne = function (id) {
return _this.data.find(function (record) { return record.id === id; }) || null;
};
this.update = function (id, params) {
var index = _this.data.findIndex(function (record) { return record.id === id; });
if (!index)
return false;
var record = _this.data[index];
_this.data[index] = __assign(__assign({}, record), params);
return _this.data[index];
};
this.delete = function (id) {
var index = _this.data.findIndex(function (record) { return record.id === id; });
if (!index)
return false;
_this.data.splice(index, 1);
return true;
};
this.data = records;
}
return DataBuddy;
}());
exports.DataBuddy = DataBuddy;

24
node_modules/@dank-inc/data-buddy/package.json generated vendored Normal file
View File

@ -0,0 +1,24 @@
{
"name": "@dank-inc/data-buddy",
"version": "0.1.3",
"author": "Elijah Lucian",
"license": "MIT",
"description": "Need a little mock api data state buddy?",
"repository": {
"type": "git",
"url": "https://github.com/dank-inc/data-buddy"
},
"files": [
"lib"
],
"main": "index.js",
"scripts": {
"lint": "tsc --noEmit",
"compile": "rm -rf lib && tsc",
"deploy": "npm run compile && npm publish",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"typescript": "^4.2.4"
}
}