stuff, with a side of things
This commit is contained in:
		
							
								
								
									
										21663
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										21663
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -6,11 +6,13 @@
 | 
				
			|||||||
    "@dank-inc/data-buddy": "^0.2.0",
 | 
					    "@dank-inc/data-buddy": "^0.2.0",
 | 
				
			||||||
    "@testing-library/react": "^11.1.0",
 | 
					    "@testing-library/react": "^11.1.0",
 | 
				
			||||||
    "@testing-library/user-event": "^12.1.10",
 | 
					    "@testing-library/user-event": "^12.1.10",
 | 
				
			||||||
 | 
					    "@types/lodash": "^4.14.171",
 | 
				
			||||||
    "@types/node": "^12.0.0",
 | 
					    "@types/node": "^12.0.0",
 | 
				
			||||||
    "@types/react": "^17.0.0",
 | 
					    "@types/react": "^17.0.0",
 | 
				
			||||||
    "@types/react-dom": "^17.0.0",
 | 
					    "@types/react-dom": "^17.0.0",
 | 
				
			||||||
    "antd": "^4.14.0",
 | 
					    "antd": "^4.14.0",
 | 
				
			||||||
    "axios": "^0.21.1",
 | 
					    "axios": "^0.21.1",
 | 
				
			||||||
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "node-sass": "^4.0.0",
 | 
					    "node-sass": "^4.0.0",
 | 
				
			||||||
    "react": "^17.0.1",
 | 
					    "react": "^17.0.1",
 | 
				
			||||||
    "react-dom": "^17.0.1",
 | 
					    "react-dom": "^17.0.1",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ import './app.scss'
 | 
				
			|||||||
const App = () => {
 | 
					const App = () => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <BrowserRouter>
 | 
					    <BrowserRouter>
 | 
				
			||||||
      <AppContextProvider>
 | 
					      <AppContextProvider baseURL="/api">
 | 
				
			||||||
        <UserContextProvider>
 | 
					        <UserContextProvider>
 | 
				
			||||||
          <CoreLayout />
 | 
					          <CoreLayout />
 | 
				
			||||||
        </UserContextProvider>
 | 
					        </UserContextProvider>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,49 +0,0 @@
 | 
				
			|||||||
import { DataBuddy } from '@dank-inc/data-buddy'
 | 
					 | 
				
			||||||
import { Account, Stack, Transaction, User } from '../../types'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const users = new DataBuddy<User>([
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'mock-user',
 | 
					 | 
				
			||||||
    name: 'TestUser42',
 | 
					 | 
				
			||||||
    email: 'testuser@email.com',
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const accounts = new DataBuddy<Account>([
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'home',
 | 
					 | 
				
			||||||
    name: 'Home Expenses',
 | 
					 | 
				
			||||||
    details: 'ya',
 | 
					 | 
				
			||||||
    users: ['42'],
 | 
					 | 
				
			||||||
    income: 1000,
 | 
					 | 
				
			||||||
    expenses: 500,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
])
 | 
					 | 
				
			||||||
export const stacks = new DataBuddy<Stack>([
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'ccrap',
 | 
					 | 
				
			||||||
    name: 'crap',
 | 
					 | 
				
			||||||
    account: 'asdf',
 | 
					 | 
				
			||||||
    amount: 200,
 | 
					 | 
				
			||||||
    details: 'for all my crap!',
 | 
					 | 
				
			||||||
    transactions: [],
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'shit',
 | 
					 | 
				
			||||||
    name: 'shit',
 | 
					 | 
				
			||||||
    account: 'home',
 | 
					 | 
				
			||||||
    amount: 500,
 | 
					 | 
				
			||||||
    details: 'for all my shit!',
 | 
					 | 
				
			||||||
    transactions: [],
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'poo',
 | 
					 | 
				
			||||||
    name: 'poo',
 | 
					 | 
				
			||||||
    account: 'home',
 | 
					 | 
				
			||||||
    amount: 800,
 | 
					 | 
				
			||||||
    details: 'for all my poo!',
 | 
					 | 
				
			||||||
    transactions: [],
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const transactions = new DataBuddy<Transaction>([])
 | 
					 | 
				
			||||||
@@ -1,8 +1,7 @@
 | 
				
			|||||||
import Axios, { AxiosInstance } from 'axios'
 | 
					import Axios, { AxiosInstance } from 'axios'
 | 
				
			||||||
import { Account, Password, Stack, Transaction, User, uuid } from '../types'
 | 
					import { Account, Password, Stack, Transaction, User } from '../types'
 | 
				
			||||||
import { JWT, setJWT, wipeJWT } from '../utils/jwt'
 | 
					import { JWT, setJWT, wipeJWT } from '../utils/jwt'
 | 
				
			||||||
import { DataBuddy } from '@dank-inc/data-buddy'
 | 
					import { DataBuddy } from '@dank-inc/data-buddy'
 | 
				
			||||||
import { users, accounts, stacks, transactions } from './data'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ApiParams = {
 | 
					export type ApiParams = {
 | 
				
			||||||
  baseURL?: string
 | 
					  baseURL?: string
 | 
				
			||||||
@@ -21,24 +20,10 @@ export interface Api {
 | 
				
			|||||||
export class Api {
 | 
					export class Api {
 | 
				
			||||||
  constructor({ mock, baseURL }: ApiParams) {
 | 
					  constructor({ mock, baseURL }: ApiParams) {
 | 
				
			||||||
    this.mock = mock
 | 
					    this.mock = mock
 | 
				
			||||||
    this.users = users
 | 
					 | 
				
			||||||
    this.accounts = accounts
 | 
					 | 
				
			||||||
    this.stacks = stacks
 | 
					 | 
				
			||||||
    this.transactions = transactions
 | 
					 | 
				
			||||||
    this.axios = Axios.create({ baseURL })
 | 
					    this.axios = Axios.create({ baseURL })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  login = async (name: string, password: string): Promise<JWT> => {
 | 
					  login = async (name: string, password: string): Promise<JWT> => {
 | 
				
			||||||
    if (this.mock) {
 | 
					 | 
				
			||||||
      const jwt = {
 | 
					 | 
				
			||||||
        id: 'mock-user',
 | 
					 | 
				
			||||||
        token: 'token-token-token',
 | 
					 | 
				
			||||||
        exp: +new Date(),
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      setJWT(jwt)
 | 
					 | 
				
			||||||
      return jwt
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { data } = await this.axios.post<JWT>(`/dj-rest-auth/login/`, {
 | 
					    const { data } = await this.axios.post<JWT>(`/dj-rest-auth/login/`, {
 | 
				
			||||||
      name,
 | 
					      name,
 | 
				
			||||||
      password,
 | 
					      password,
 | 
				
			||||||
@@ -49,18 +34,15 @@ export class Api {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  logout = () => {
 | 
					  logout = () => {
 | 
				
			||||||
    if (this.mock) return true
 | 
					 | 
				
			||||||
    wipeJWT()
 | 
					    wipeJWT()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getUser = async (id: uuid) => {
 | 
					  getUser = async (id: string) => {
 | 
				
			||||||
    if (this.mock) return this.users.getOne(id)
 | 
					 | 
				
			||||||
    const { data } = await this.axios.get<User>(`users/${id}`)
 | 
					    const { data } = await this.axios.get<User>(`users/${id}`)
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateUser = async (id: uuid, body: Partial<User>) => {
 | 
					  updateUser = async (id: string, body: Partial<User>) => {
 | 
				
			||||||
    if (this.mock) return this.users.update(id, body)
 | 
					 | 
				
			||||||
    const { data } = await this.axios.patch<User>(`users/${id}`, body)
 | 
					    const { data } = await this.axios.patch<User>(`users/${id}`, body)
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -71,17 +53,15 @@ export class Api {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getAccounts = async () => {
 | 
					  getAccounts = async () => {
 | 
				
			||||||
    if (this.mock) return this.accounts.get()
 | 
					 | 
				
			||||||
    const { data } = await this.axios.get<Account[]>('accounts')
 | 
					    const { data } = await this.axios.get<Account[]>('accounts')
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getAccount = async (id: uuid) => {
 | 
					  getAccount = async (id: string) => {
 | 
				
			||||||
    if (this.mock) return this.accounts.getOne(id)
 | 
					 | 
				
			||||||
    const data = await this.axios.get<Account>(`accounts/${id}`)
 | 
					    const data = await this.axios.get<Account>(`accounts/${id}`)
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  updateAccount = async (id: uuid, body: Partial<Account>) => {
 | 
					  updateAccount = async (id: string, body: Partial<Account>) => {
 | 
				
			||||||
    const { data } = await this.axios.patch<Account>(`accounts/${id}`, body)
 | 
					    const { data } = await this.axios.patch<Account>(`accounts/${id}`, body)
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -92,12 +72,11 @@ export class Api {
 | 
				
			|||||||
  deleteAccount = async () => {}
 | 
					  deleteAccount = async () => {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getStacks = async (): Promise<Stack[]> => {
 | 
					  getStacks = async (): Promise<Stack[]> => {
 | 
				
			||||||
    if (this.mock) return this.stacks.get()
 | 
					 | 
				
			||||||
    const { data } = await this.axios.get('stacks')
 | 
					    const { data } = await this.axios.get('stacks')
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateStack = async (id: uuid, body: Partial<Stack>) => {
 | 
					  updateStack = async (id: string, body: Partial<Stack>) => {
 | 
				
			||||||
    const { data } = await this.axios.patch<Stack>(`stacks/${id}`, body)
 | 
					    const { data } = await this.axios.patch<Stack>(`stacks/${id}`, body)
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -106,12 +85,11 @@ export class Api {
 | 
				
			|||||||
  deleteStack = async () => {}
 | 
					  deleteStack = async () => {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getTransactions = async () => {
 | 
					  getTransactions = async () => {
 | 
				
			||||||
    if (this.mock) return this.transactions.get()
 | 
					 | 
				
			||||||
    const { data } = await this.axios.get('transactions')
 | 
					    const { data } = await this.axios.get('transactions')
 | 
				
			||||||
    return data
 | 
					    return data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateTransaction = async (id: uuid, body: Partial<Transaction>) => {
 | 
					  updateTransaction = async (id: string, body: Partial<Transaction>) => {
 | 
				
			||||||
    const { data } = await this.axios.patch<Transaction>(
 | 
					    const { data } = await this.axios.patch<Transaction>(
 | 
				
			||||||
      `transactions/${id}`,
 | 
					      `transactions/${id}`,
 | 
				
			||||||
      body,
 | 
					      body,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import Axios, { AxiosResponse } from 'axios'
 | 
					import axios, { AxiosResponse } from 'axios'
 | 
				
			||||||
import React, { createContext, useContext } from 'react'
 | 
					import React, { createContext, useContext } from 'react'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
@@ -6,7 +6,7 @@ type Props = {
 | 
				
			|||||||
  baseURL?: string
 | 
					  baseURL?: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Context = {
 | 
					type AppContextInterface = {
 | 
				
			||||||
  get: <T>(path: string) => Promise<T>
 | 
					  get: <T>(path: string) => Promise<T>
 | 
				
			||||||
  patch: <T>(path: string, body: Partial<T>) => Promise<T>
 | 
					  patch: <T>(path: string, body: Partial<T>) => Promise<T>
 | 
				
			||||||
  post: <T, R = T>(path: string, body: Partial<T>) => Promise<R>
 | 
					  post: <T, R = T>(path: string, body: Partial<T>) => Promise<R>
 | 
				
			||||||
@@ -14,30 +14,35 @@ type Context = {
 | 
				
			|||||||
  destroy: (path: string) => Promise<string>
 | 
					  destroy: (path: string) => Promise<string>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AppContext = createContext<Context | null>(null)
 | 
					const AppContext = createContext<AppContextInterface | null>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const AppContextProvider = ({ children, baseURL }: Props) => {
 | 
					export const AppContextProvider = ({ children, baseURL }: Props) => {
 | 
				
			||||||
  const axios = Axios.create({ baseURL })
 | 
					  const api = axios.create({ baseURL })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  api.interceptors.request.use((config) => {
 | 
				
			||||||
 | 
					    config.url += '?format=json'
 | 
				
			||||||
 | 
					    return config
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async function get<T>(path: string): Promise<T> {
 | 
					  async function get<T>(path: string): Promise<T> {
 | 
				
			||||||
    const res = await axios.get<T>(path)
 | 
					    const res = await api.get<T>(path)
 | 
				
			||||||
    return res.data
 | 
					    return res.data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  async function patch<T>(path: string, body: Partial<T>) {
 | 
					  async function patch<T>(path: string, body: Partial<T>) {
 | 
				
			||||||
    const res = await axios.patch<T>(path, body)
 | 
					    const res = await api.patch<T>(path, body)
 | 
				
			||||||
    return res.data
 | 
					    return res.data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  async function post<T, R = T>(path: string, body: Partial<T>) {
 | 
					  async function post<T, R = T>(path: string, body: Partial<T>) {
 | 
				
			||||||
    const res = await axios.post<T, AxiosResponse<R>>(path, body)
 | 
					    const res = await api.post<T, AxiosResponse<R>>(path, body)
 | 
				
			||||||
    return res.data
 | 
					    return res.data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  async function create<T>(path: string, body: Partial<T>) {
 | 
					  async function create<T>(path: string, body: Partial<T>) {
 | 
				
			||||||
    // unauthed POST
 | 
					    // unauthed POST
 | 
				
			||||||
    const res = await axios.post<T>(path, body)
 | 
					    const res = await api.post<T>(path, body)
 | 
				
			||||||
    return res.data
 | 
					    return res.data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  async function destroy(path: string) {
 | 
					  async function destroy(path: string) {
 | 
				
			||||||
    const res = await axios.delete<string>(path)
 | 
					    const res = await api.delete<string>(path)
 | 
				
			||||||
    return res.data
 | 
					    return res.data
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import React, { createContext, useContext, useState } from 'react'
 | 
					import React, { createContext, useContext, useState } from 'react'
 | 
				
			||||||
import { message } from 'antd'
 | 
					import { message } from 'antd'
 | 
				
			||||||
import { useHistory } from 'react-router'
 | 
					import { useHistory } from 'react-router'
 | 
				
			||||||
import { Account, User, uuid } from '../types'
 | 
					import { User } from '../types'
 | 
				
			||||||
import { useAppContext } from './AppContext'
 | 
					import { useAppContext } from './AppContext'
 | 
				
			||||||
import { logOut } from '../api'
 | 
					import { logOut } from '../api'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -11,11 +11,8 @@ type Props = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type Context = {
 | 
					type Context = {
 | 
				
			||||||
  user: User | null
 | 
					  user: User | null
 | 
				
			||||||
  accounts: Account[] | null
 | 
					 | 
				
			||||||
  selectedAccount: Account | null
 | 
					 | 
				
			||||||
  handleLogin: (name: string, password: string) => void
 | 
					  handleLogin: (name: string, password: string) => void
 | 
				
			||||||
  handleLogout: () => void
 | 
					  handleLogout: () => void
 | 
				
			||||||
  handleSelectAccount: (id: uuid) => void
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const UserContext = createContext<Context | null>(null)
 | 
					const UserContext = createContext<Context | null>(null)
 | 
				
			||||||
@@ -25,10 +22,10 @@ export const UserContextProvider = ({ children }: Props) => {
 | 
				
			|||||||
  const history = useHistory()
 | 
					  const history = useHistory()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [user, setUser] = useState<User | null>(null)
 | 
					  const [user, setUser] = useState<User | null>(null)
 | 
				
			||||||
  const [accounts, setAccounts] = useState<Account[] | null>(null)
 | 
					 | 
				
			||||||
  const [selectedAccount, setSelectedAccount] = useState<Account | null>(null)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleLogin = async (name: string, password: string) => {
 | 
					  const handleLogin = async (name: string, password: string) => {
 | 
				
			||||||
 | 
					    console.log('logging in?', name, password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const { id } = await api.post<any, { id: string }>('/login', {
 | 
					      const { id } = await api.post<any, { id: string }>('/login', {
 | 
				
			||||||
        name,
 | 
					        name,
 | 
				
			||||||
@@ -40,9 +37,6 @@ export const UserContextProvider = ({ children }: Props) => {
 | 
				
			|||||||
      if (!user) message.error(`Couldn't find user`)
 | 
					      if (!user) message.error(`Couldn't find user`)
 | 
				
			||||||
      setUser(user)
 | 
					      setUser(user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const accounts = await api.get<Account[]>('/accounts')
 | 
					 | 
				
			||||||
      setAccounts(accounts)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      message.success(`logged in as ${user?.name}`, 0.5)
 | 
					      message.success(`logged in as ${user?.name}`, 0.5)
 | 
				
			||||||
    } catch (err) {
 | 
					    } catch (err) {
 | 
				
			||||||
      message.error('Login Failed!')
 | 
					      message.error('Login Failed!')
 | 
				
			||||||
@@ -56,20 +50,12 @@ export const UserContextProvider = ({ children }: Props) => {
 | 
				
			|||||||
    history.push('/')
 | 
					    history.push('/')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleSelectAccount = (id: string) => {
 | 
					 | 
				
			||||||
    const account = accounts?.find((account) => account.id === id)
 | 
					 | 
				
			||||||
    if (account) setSelectedAccount(account)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <UserContext.Provider
 | 
					    <UserContext.Provider
 | 
				
			||||||
      value={{
 | 
					      value={{
 | 
				
			||||||
        user,
 | 
					        user,
 | 
				
			||||||
        accounts,
 | 
					 | 
				
			||||||
        handleLogin,
 | 
					        handleLogin,
 | 
				
			||||||
        handleLogout,
 | 
					        handleLogout,
 | 
				
			||||||
        selectedAccount,
 | 
					 | 
				
			||||||
        handleSelectAccount,
 | 
					 | 
				
			||||||
      }}
 | 
					      }}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {children}
 | 
					      {children}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
import { Button as AntButton, ButtonProps } from 'antd'
 | 
					import { Button as AntButton, ButtonProps } from 'antd'
 | 
				
			||||||
import React from 'react'
 | 
					 | 
				
			||||||
import './style.scss'
 | 
					import './style.scss'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = ButtonProps
 | 
					type Props = ButtonProps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Button = ({ children, htmlType }: Props) => {
 | 
					export const Button = ({ children, ...props }: Props) => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <AntButton className="dank-button" htmlType={htmlType}>
 | 
					    <AntButton className="dank-button" {...props}>
 | 
				
			||||||
      {children}
 | 
					      {children}
 | 
				
			||||||
    </AntButton>
 | 
					    </AntButton>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,10 @@ import './style.scss'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type Props = FormProps
 | 
					type Props = FormProps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Form = ({ children }: Props) => {
 | 
					export const Form = ({ children, ...props }: Props) => {
 | 
				
			||||||
  return <AntForm className="dank-form">{children}</AntForm>
 | 
					  return (
 | 
				
			||||||
 | 
					    <AntForm className="dank-form" {...props}>
 | 
				
			||||||
 | 
					      {children}
 | 
				
			||||||
 | 
					    </AntForm>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
import { Account } from '../../types'
 | 
					import { Account } from '../../types'
 | 
				
			||||||
import { useGet } from '../util/useGet'
 | 
					import { useGet } from '../util/useGet'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useAccounts = (userId: string) =>
 | 
					export const useAccounts = () => useGet<Account[]>(`/accounts`)
 | 
				
			||||||
  useGet<Account[]>(`/users/${userId}/accounts`)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
import { Stack } from '../../types'
 | 
					import { Stack } from '../../types'
 | 
				
			||||||
import { useGet } from '../util/useGet'
 | 
					import { useGet } from '../util/useGet'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useStacks = (accountId: string) =>
 | 
					export const useStacks = (accountId: string) => useGet<Stack[]>(`/stacks`)
 | 
				
			||||||
  useGet<Stack[]>(`/accounts/${accountId}/stacks`)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,15 @@
 | 
				
			|||||||
import { useCallback, useEffect, useRef, useState } from 'react'
 | 
					import { useCallback, useEffect, useRef, useState } from 'react'
 | 
				
			||||||
import { useAppContext } from '../../contexts/AppContext'
 | 
					import { useAppContext } from '../../contexts/AppContext'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Res<T> = {
 | 
					 | 
				
			||||||
  data: T
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useGet = <T>(path: string) => {
 | 
					export const useGet = <T>(path: string) => {
 | 
				
			||||||
  const appContext = useRef(useAppContext())
 | 
					  const appContext = useRef(useAppContext())
 | 
				
			||||||
  const [data, setData] = useState<T | null>(null)
 | 
					  const [data, setData] = useState<T | null>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const get = useCallback(async () => {
 | 
					  const get = useCallback(async () => {
 | 
				
			||||||
    // if (appContext.current.mock) return setData(mockGet[path]?.() || null)
 | 
					    const data = await appContext.current.get<T>(path)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const data = await appContext.current.get<Res<T>>(path)
 | 
					 | 
				
			||||||
    if (!data) return
 | 
					    if (!data) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setData(data.data)
 | 
					    setData(data)
 | 
				
			||||||
  }, [path])
 | 
					  }, [path])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import { FundBar } from '../../widgets/FundBar'
 | 
				
			|||||||
import { useStacks } from '../../hooks/getMany/useStacks'
 | 
					import { useStacks } from '../../hooks/getMany/useStacks'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Dashboard = () => {
 | 
					export const Dashboard = () => {
 | 
				
			||||||
  const stacks = useStacks('')
 | 
					  const stacks = useStacks('42')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!stacks.data) return <div>loading...</div>
 | 
					  if (!stacks.data) return <div>loading...</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,28 +1,33 @@
 | 
				
			|||||||
import { Input } from 'antd'
 | 
					import { Input } from 'antd'
 | 
				
			||||||
import FormItem from 'antd/lib/form/FormItem'
 | 
					import FormItem from 'antd/lib/form/FormItem'
 | 
				
			||||||
import { Link } from 'react-router-dom'
 | 
					import { Link } from 'react-router-dom'
 | 
				
			||||||
import { User } from '../../types'
 | 
					 | 
				
			||||||
import { useUserContext } from '../../contexts/UserContext'
 | 
					 | 
				
			||||||
import { Form } from '../../elements/Form'
 | 
					import { Form } from '../../elements/Form'
 | 
				
			||||||
import { Button } from '../../elements/Button'
 | 
					import { Button } from '../../elements/Button'
 | 
				
			||||||
import { useForm } from 'antd/lib/form/Form'
 | 
					import { useForm } from 'antd/lib/form/Form'
 | 
				
			||||||
 | 
					import { useAppContext } from '../../contexts/AppContext'
 | 
				
			||||||
 | 
					import { useStacks } from '../../hooks/getMany/useStacks'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FormValues = Pick<User, 'name'> & { password: string }
 | 
					type FormValues = { email: string; password: string }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Login = () => {
 | 
					export const Login = () => {
 | 
				
			||||||
  const userContext = useUserContext()
 | 
					  const appContext = useAppContext()
 | 
				
			||||||
 | 
					  const stacks = useStacks('')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [form] = useForm<FormValues>()
 | 
					  const [form] = useForm<FormValues>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleFinish = ({ name, password }: FormValues) => {
 | 
					  const handleFinish = async ({ email, password }: FormValues) => {
 | 
				
			||||||
    userContext.handleLogin(name, password)
 | 
					    const res = await appContext.post('/dj-rest-auth/login', {
 | 
				
			||||||
 | 
					      email,
 | 
				
			||||||
 | 
					      password,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    console.log(res)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="login">
 | 
					    <div className="login">
 | 
				
			||||||
      <Form onFinish={handleFinish} form={form}>
 | 
					      <Form onFinish={handleFinish} form={form}>
 | 
				
			||||||
        <h1>Log In</h1>
 | 
					        <h1>Log In</h1>
 | 
				
			||||||
        <FormItem label="Username" name="username">
 | 
					        <FormItem label="email" name="email">
 | 
				
			||||||
          <Input />
 | 
					          <Input />
 | 
				
			||||||
        </FormItem>
 | 
					        </FormItem>
 | 
				
			||||||
        <FormItem label="Password" name="password">
 | 
					        <FormItem label="Password" name="password">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,32 +0,0 @@
 | 
				
			|||||||
import { Button, Form, Input } from 'antd'
 | 
					 | 
				
			||||||
import { useForm } from 'antd/lib/form/Form'
 | 
					 | 
				
			||||||
import { useUserContext } from '../../contexts/UserContext'
 | 
					 | 
				
			||||||
import './style.scss'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Credentials = {
 | 
					 | 
				
			||||||
  username: string
 | 
					 | 
				
			||||||
  password: string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const Login = () => {
 | 
					 | 
				
			||||||
  const { handleLogin } = useUserContext()
 | 
					 | 
				
			||||||
  const [form] = useForm<Credentials>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleSubmit = ({ username, password }: Credentials) => {
 | 
					 | 
				
			||||||
    handleLogin(username, password)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <Form form={form} onFinish={handleSubmit}>
 | 
					 | 
				
			||||||
      <Form.Item label="username" name="username">
 | 
					 | 
				
			||||||
        <Input />
 | 
					 | 
				
			||||||
      </Form.Item>
 | 
					 | 
				
			||||||
      <Form.Item label="password" name="password">
 | 
					 | 
				
			||||||
        <Input type="password" />
 | 
					 | 
				
			||||||
      </Form.Item>
 | 
					 | 
				
			||||||
      <Button type="primary" htmlType="submit">
 | 
					 | 
				
			||||||
        Login!
 | 
					 | 
				
			||||||
      </Button>
 | 
					 | 
				
			||||||
    </Form>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -11,7 +11,6 @@ export const NewUser = () => {
 | 
				
			|||||||
  const [form] = Form.useForm<NewUserForm>()
 | 
					  const [form] = Form.useForm<NewUserForm>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleFinish = (user: NewUserForm) => {
 | 
					  const handleFinish = (user: NewUserForm) => {
 | 
				
			||||||
    console.log('Asdfdas')
 | 
					 | 
				
			||||||
    if (user.password1 !== user.password2) {
 | 
					    if (user.password1 !== user.password2) {
 | 
				
			||||||
      message.error('passwords do not match')
 | 
					      message.error('passwords do not match')
 | 
				
			||||||
      return
 | 
					      return
 | 
				
			||||||
@@ -20,29 +19,23 @@ export const NewUser = () => {
 | 
				
			|||||||
    axios.post(`/dj-rest-auth/registration/`, user)
 | 
					    axios.post(`/dj-rest-auth/registration/`, user)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log('ASDFUASDJF')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Layout>
 | 
					    <Form form={form} onFinish={handleFinish}>
 | 
				
			||||||
      <Layout.Content>
 | 
					      <Form.Item label="username" name="username">
 | 
				
			||||||
        <Form form={form} onFinish={handleFinish}>
 | 
					        <Input></Input>
 | 
				
			||||||
          <Form.Item label="username" name="username">
 | 
					      </Form.Item>
 | 
				
			||||||
            <Input></Input>
 | 
					      <Form.Item label="email" name="email">
 | 
				
			||||||
          </Form.Item>
 | 
					        <Input type="email"></Input>
 | 
				
			||||||
          <Form.Item label="email" name="email">
 | 
					      </Form.Item>
 | 
				
			||||||
            <Input type="email"></Input>
 | 
					      <Form.Item label="password" name="password1">
 | 
				
			||||||
          </Form.Item>
 | 
					        <Input minLength={8}></Input>
 | 
				
			||||||
          <Form.Item label="password" name="password1">
 | 
					      </Form.Item>
 | 
				
			||||||
            <Input minLength={8}></Input>
 | 
					      <Form.Item label="confirm" name="password2">
 | 
				
			||||||
          </Form.Item>
 | 
					        <Input></Input>
 | 
				
			||||||
          <Form.Item label="confirm" name="password2">
 | 
					      </Form.Item>
 | 
				
			||||||
            <Input></Input>
 | 
					      <Button type="primary" htmlType="submit">
 | 
				
			||||||
          </Form.Item>
 | 
					        Create
 | 
				
			||||||
          <Button type="primary" htmlType="submit">
 | 
					      </Button>
 | 
				
			||||||
            Create
 | 
					    </Form>
 | 
				
			||||||
          </Button>
 | 
					 | 
				
			||||||
        </Form>
 | 
					 | 
				
			||||||
      </Layout.Content>
 | 
					 | 
				
			||||||
    </Layout>
 | 
					 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,13 @@
 | 
				
			|||||||
export type uuid = string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type User = {
 | 
					export type User = {
 | 
				
			||||||
  id: uuid
 | 
					  id: string
 | 
				
			||||||
  name: string
 | 
					  name: string
 | 
				
			||||||
  email: string
 | 
					  email: string
 | 
				
			||||||
  // password: string
 | 
					  // password: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Account = {
 | 
					export type Account = {
 | 
				
			||||||
  id: uuid
 | 
					  id: string
 | 
				
			||||||
  users?: uuid[]
 | 
					  users?: string[]
 | 
				
			||||||
  name: string
 | 
					  name: string
 | 
				
			||||||
  details: string
 | 
					  details: string
 | 
				
			||||||
  income: number
 | 
					  income: number
 | 
				
			||||||
@@ -17,8 +15,8 @@ export type Account = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Stack = {
 | 
					export type Stack = {
 | 
				
			||||||
  id: uuid
 | 
					  id: string
 | 
				
			||||||
  account: uuid //'38485982-87f3-4a11-a963-2202983809e3'
 | 
					  account: string //'38485982-87f3-4a11-a963-2202983809e3'
 | 
				
			||||||
  name: string // 'House Fund'
 | 
					  name: string // 'House Fund'
 | 
				
			||||||
  details: string //'buy furniture'
 | 
					  details: string //'buy furniture'
 | 
				
			||||||
  amount: number // '200.00'
 | 
					  amount: number // '200.00'
 | 
				
			||||||
@@ -26,8 +24,8 @@ export type Stack = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Transaction = {
 | 
					export type Transaction = {
 | 
				
			||||||
  id: uuid
 | 
					  id: string
 | 
				
			||||||
  stack: uuid // '0058cece-3ff3-4ee1-b71d-075a0bc73bc0'
 | 
					  stack: string // '0058cece-3ff3-4ee1-b71d-075a0bc73bc0'
 | 
				
			||||||
  details: string // 'by ghetto couch off Kijiji'
 | 
					  details: string // 'by ghetto couch off Kijiji'
 | 
				
			||||||
  amount: number // '30.44'
 | 
					  amount: number // '30.44'
 | 
				
			||||||
  created_at: string // '2021-04-15T00:02:45.096071Z'
 | 
					  created_at: string // '2021-04-15T00:02:45.096071Z'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,15 @@
 | 
				
			|||||||
import { Link } from 'react-router-dom'
 | 
					import { Link } from 'react-router-dom'
 | 
				
			||||||
import { message } from 'antd'
 | 
					import { message } from 'antd'
 | 
				
			||||||
import { useUserContext } from '../../contexts/UserContext'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import './style.scss'
 | 
					import './style.scss'
 | 
				
			||||||
import { Button } from '../../elements/Button'
 | 
					import { Button } from '../../elements/Button'
 | 
				
			||||||
 | 
					import { useAccounts } from '../../hooks/getMany/useAccounts'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
  selectProfile: (id: string) => void
 | 
					  selectProfile: (id: string) => void
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const AccountSelect = ({ selectProfile }: Props) => {
 | 
					export const AccountSelect = ({ selectProfile }: Props) => {
 | 
				
			||||||
  const { accounts } = useUserContext()
 | 
					  const accounts = useAccounts()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleSelect = (id: string) => {
 | 
					  const handleSelect = (id: string) => {
 | 
				
			||||||
    selectProfile(id)
 | 
					    selectProfile(id)
 | 
				
			||||||
@@ -21,16 +20,14 @@ export const AccountSelect = ({ selectProfile }: Props) => {
 | 
				
			|||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <h1>Select Account</h1>
 | 
					      <h1>Select Account</h1>
 | 
				
			||||||
      <div className="account-select">
 | 
					      <div className="account-select">
 | 
				
			||||||
        {accounts?.length
 | 
					        {accounts.data?.map((account) => (
 | 
				
			||||||
          ? accounts.map((account) => (
 | 
					          <Button
 | 
				
			||||||
              <Button
 | 
					            key={`account-${account.name}`}
 | 
				
			||||||
                key={`account-${account.name}`}
 | 
					            onClick={() => handleSelect(account.id)}
 | 
				
			||||||
                onClick={() => handleSelect(account.id)}
 | 
					          >
 | 
				
			||||||
              >
 | 
					            {account.name}
 | 
				
			||||||
                {account.name}
 | 
					          </Button>
 | 
				
			||||||
              </Button>
 | 
					        ))}
 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
          : ''}
 | 
					 | 
				
			||||||
        <Link to="/account/new">Create New Budget!</Link>
 | 
					        <Link to="/account/new">Create New Budget!</Link>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1784,6 +1784,11 @@
 | 
				
			|||||||
  "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
 | 
					  "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
 | 
				
			||||||
  "version" "0.0.29"
 | 
					  "version" "0.0.29"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@types/lodash@^4.14.171":
 | 
				
			||||||
 | 
					  "integrity" "sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg=="
 | 
				
			||||||
 | 
					  "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.171.tgz"
 | 
				
			||||||
 | 
					  "version" "4.14.171"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@types/minimatch@*":
 | 
					"@types/minimatch@*":
 | 
				
			||||||
  "integrity" "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA=="
 | 
					  "integrity" "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA=="
 | 
				
			||||||
  "resolved" "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz"
 | 
					  "resolved" "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz"
 | 
				
			||||||
@@ -4164,11 +4169,6 @@
 | 
				
			|||||||
  "resolved" "https://registry.npmjs.org/date-fns/-/date-fns-2.21.0.tgz"
 | 
					  "resolved" "https://registry.npmjs.org/date-fns/-/date-fns-2.21.0.tgz"
 | 
				
			||||||
  "version" "2.21.0"
 | 
					  "version" "2.21.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"dayjs@^1.8.30":
 | 
					 | 
				
			||||||
  "integrity" "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw=="
 | 
					 | 
				
			||||||
  "resolved" "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz"
 | 
					 | 
				
			||||||
  "version" "1.10.4"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"debug@^2.2.0":
 | 
					"debug@^2.2.0":
 | 
				
			||||||
  "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
 | 
					  "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
 | 
				
			||||||
  "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
 | 
					  "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
users:
 | 
					users:
 | 
				
			||||||
  - name: elijah
 | 
					  - name: elijah
 | 
				
			||||||
    password: toffee15
 | 
					    password: toffee15
 | 
				
			||||||
  - name: toffee
 | 
					  - name: ievgen
 | 
				
			||||||
 | 
					    password: toffee15
 | 
				
			||||||
 | 
					  - name: tanner
 | 
				
			||||||
    password: toffee15
 | 
					    password: toffee15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
accounts:
 | 
					accounts:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user