Skip to content

Commit

Permalink
add allowence payments
Browse files Browse the repository at this point in the history
  • Loading branch information
dandrewgarvin committed Oct 19, 2021
1 parent be10783 commit b62b797
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 38 deletions.
21 changes: 18 additions & 3 deletions app/data/UserContext.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React from 'react';
import React, { useState } from 'react';
import { Person } from '~/types/people';

interface IUserContext {
people: Array<Person>;
selecting: boolean;
selectedPeople?: Array<Person>;
setSelectedPeople(people: Array<Person>): void;
}

const Context = React.createContext<IUserContext | null>(null);
Expand All @@ -17,9 +20,21 @@ const useUsers = () => {
return context;
};

const UserContext: React.FC<Partial<IUserContext>> = ({ children, people }) => {
const UserContext: React.FC<Partial<IUserContext>> = ({
children,
people,
selecting = false,
}) => {
const [selectedPeople, setSelectedPeople] = useState<Array<Person>>([]);
return (
<Context.Provider value={{ people: people ?? [] }}>
<Context.Provider
value={{
people: people ?? [],
selecting: selecting,
selectedPeople,
setSelectedPeople,
}}
>
{children}
</Context.Provider>
);
Expand Down
149 changes: 131 additions & 18 deletions app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import {
ActionFunction,
MetaFunction,
LinksFunction,
LoaderFunction,
useLoaderData,
} from 'remix';
import { Meta, Links, Scripts, LiveReload, useCatch } from 'remix';
import { Outlet } from 'react-router-dom';
import {
Meta,
Links,
Scripts,
LiveReload,
useCatch,
useSubmit,
redirect,
} from 'remix';
import { Outlet, useNavigate, useLocation } from 'react-router-dom';

import UserContext from './data/UserContext';
import UserContext, { useUsers } from './data/UserContext';

import Header from './components/Header';
import type { Route } from './components/Header';
Expand Down Expand Up @@ -41,6 +50,50 @@ export let loader: LoaderFunction = async () => {
};
};

export let action: ActionFunction = async ({ params, request }) => {
const response = await fetch(
'https://api.github.com/gists/843c7ffbe1073bdaf45cfc48b86264c1',
{
headers: {
Authorization: `token ${process.env.GITHUB_TOKEN}`,
},
}
);

const data = await response.json();
let people = JSON.parse(data.files.people.content);

let body = new URLSearchParams(await request.text());
let selected: Array<Person> = JSON.parse(body.get('selected') ?? '');

const ALLOWENCE = 350;
people = people.map((person: Person) => {
if (selected.find(s => s.name === person.name)) {
return {
name: person.name,
bank: person.bank + ALLOWENCE,
imageUrl: person.imageUrl,
};
}

return person;
});

await fetch('https://api.github.com/gists/843c7ffbe1073bdaf45cfc48b86264c1', {
method: 'patch',
headers: {
Authorization: `token ${process.env.GITHUB_TOKEN}`,
},
body: JSON.stringify({
files: {
people: { content: JSON.stringify(people, null, 2) },
},
}),
});

return redirect('?selecting=false');
};

export let meta: MetaFunction = () => {
return {
title: 'Poker Bank',
Expand All @@ -59,6 +112,7 @@ function Document({
<head>
<meta charSet='utf-8' />
<link rel='icon' href='/favicon.png' type='image/png' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
{title ? <title>{title}</title> : null}
<Meta />
<Links />
Expand All @@ -72,16 +126,40 @@ function Document({
);
}

const navigation = [
{ name: 'Chip Bank', title: 'Overview', href: '/' },
// { name: 'Chips', href: '/chips' },
// { name: 'Profile', href: '/profile' },
];
const navigation = [{ name: 'Chip Bank', title: 'Overview', href: '/' }];

const useQueryParams = () => {
return new URLSearchParams(useLocation().search);
};

export default function App() {
const submit = useSubmit();
const navigate = useNavigate();
const queryParams = useQueryParams();
const location = useLocation();

const { people } = useLoaderData();

const [activeRoute, setActiveRoute] = useState<Route>(navigation[0]);
const [selecting, setSelecting] = useState(false);
const [selectedPeople, setSelectedPeople] = useState<Array<Person>>([]);

const handleDistribute = useCallback(() => {
const form = new FormData();
form.set('selected', JSON.stringify(selectedPeople));

submit(form, { method: 'post' });
}, [selectedPeople]);

useEffect(() => {
const isSelecting = queryParams.get('selecting');

if (isSelecting !== null) {
setSelecting(false);
setSelectedPeople([]);
navigate('/');
}
}, [location.search]);

return (
<Document>
Expand All @@ -93,28 +171,63 @@ export default function App() {
/>
<div className='bg-gray-800 pb-32'>
<header className='py-10'>
<div className='max-w-7xl mx-auto px-4 sm:px-6 lg:px-8'>
<div className='max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex justify-between'>
<h1 className='text-3xl font-bold text-white'>
{activeRoute.name}
</h1>

<span className='flex'>
<button
className='text-white btn p-2 rounded bg-indigo-500'
onClick={() => setSelecting(!selecting)}
>
{!selecting ? 'Stimmy Payments' : 'Cancel Stimmys'}
</button>
{selecting && (
<button
className='text-white btn p-2 rounded bg-indigo-500 ml-2'
onClick={() => handleDistribute()}
>
Distribute Stimmys
</button>
)}
</span>
</div>
</header>
</div>

<UserContext people={people}>
<main className='-mt-32'>
<div className='max-w-7xl mx-auto pb-12 px-4 sm:px-6 lg:px-8'>
<div className='bg-white rounded-lg shadow px-5 py-6 sm:px-6'>
<Outlet />
</div>
</div>
</main>
<UserContext people={people} selecting={selecting}>
<Main handleSelectedPeople={setSelectedPeople} />
</UserContext>
</div>
</Document>
);
}

const Main = ({
handleSelectedPeople,
}: {
handleSelectedPeople(people: Array<Person>): void;
}) => {
const { selectedPeople } = useUsers();

useEffect(() => {
if (selectedPeople) {
handleSelectedPeople(selectedPeople);
}
}, [selectedPeople]);

return (
<main className='-mt-32'>
<div className='max-w-7xl mx-auto pb-12 px-4 sm:px-6 lg:px-8'>
<div className='bg-white rounded-lg shadow px-5 py-6 sm:px-6'>
<Outlet />
</div>
</div>
</main>
);
};

export function CatchBoundary() {
let caught = useCatch();

Expand Down
72 changes: 55 additions & 17 deletions app/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
import { useCallback, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { Person } from '~/types/people';

import { useUsers } from '../data/UserContext';

const Index = () => {
const { people } = useUsers();
const { people, selecting, setSelectedPeople } = useUsers();
const [selected, setSelected] = useState<Array<Person>>([]);

const handleSelectUser = useCallback(
(user: Person) => {
if (selected.find(u => user.name === u.name)) {
let newSelected = [...selected];
newSelected = newSelected.filter(u => u.name !== user.name);
setSelected(newSelected);
} else {
const newSelected = [...selected];
newSelected.push(user);
setSelected(newSelected);
}
},
[selected]
);

useEffect(() => {
if (!selecting) {
setSelected([]);
}
}, [selecting]);

useEffect(() => {
setSelectedPeople(selected);
}, [selected]);

return (
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2'>
Expand All @@ -19,29 +47,39 @@ const Index = () => {
return 0;
})
.map((person, index) => {
const isSelected = selected.find(u => u.name === person.name);
let cardColor = '';

switch (index) {
case 0:
cardColor =
'bg-yellow-300 bg-opacity-50 border-yellow-300 hover:border-yellow-500';
break;
case 1:
cardColor = 'bg-gray-200 border-gray-300';
break;
case 2:
cardColor =
'bg-yellow-700 bg-opacity-25 border-yellow-300 hover:border-yellow-600';
break;
default:
cardColor = 'bg-white border-gray-300';
break;
if (!selecting) {
switch (index) {
case 0:
cardColor =
'bg-yellow-300 bg-opacity-50 border-yellow-300 hover:border-yellow-500';
break;
case 1:
cardColor = 'bg-gray-200 border-gray-300';
break;
case 2:
cardColor =
'bg-yellow-700 bg-opacity-25 border-yellow-300 hover:border-yellow-600';
break;
default:
cardColor = 'bg-white border-gray-300';
break;
}
} else {
if (isSelected) {
cardColor = 'bg-green-500 bg-opacity-20';
}
}

return (
<Link
key={person.name}
to={`/profile/${person.name.replace(' ', '-')}`}
onClick={() => selecting && handleSelectUser(person)}
to={
!selecting ? `/profile/${person.name.replace(' ', '-')}` : '#'
}
className={`relative rounded-lg border px-6 py-5 shadow-sm flex items-center space-x-3 hover:border-gray-400 focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500 ${cardColor}`}
>
<div className='flex-shrink-0'>
Expand Down

0 comments on commit b62b797

Please sign in to comment.