Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
jtjun committed Jul 6, 2019
2 parents 922944d + c9f6559 commit 3096b5c
Show file tree
Hide file tree
Showing 17 changed files with 138 additions and 48 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ matrix:
- pipenv run python src/manage.py test
- language: node_js
node_js: 8
install:
- npm install
before_install:
- cd frontend
script:
- npm test
4 changes: 3 additions & 1 deletion backend/src/dutch_broomstick/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ def get_queryset(self):

class RoomListCreateView(generics.ListCreateAPIView):
permission_classes = (CheckUsername,)
queryset = Room.objects.all()
serializer_class = RoomSerializer

def get_queryset(self):
return Room.objects.filter(owner=self.request.user)

def perform_create(self, serializer):
serializer.save(owner=self.request.user)

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const App = () => {
<Route path="/user/setting/" component={UserInfoPage} exact />
<Route path="/user/create_room/" component={RoomCreatePage} exact />
<Route path="/user/:room_id/entrance/" component={EntrancePage} />
<Route path="/room/:room_id/payment/" component={PaymentPage} />
<Route path="/room/:room_id/payment/" component={PaymentPage} exact />
<Route path="/room/:room_id/payment/:payment_id/" component={PaymentPage} exact />
<Route path="/room/:room_id/setting/" component={RoomSettingPage} />
<Route path="/room/:room_id/member/:member/" component={IndividualPage} exact />
<Route path="/room/:room_id/member/:member/:to" component={AccountPage} />
Expand Down
15 changes: 13 additions & 2 deletions frontend/src/components/atoms/Block/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import styled from 'styled-components'
import PropTypes from 'prop-types'

const alignItems = ({direction}) => (
direction === 'column' ?
'center' : 'baseline'
)

const Block = styled.div`
background-color: ${props => props.transparent ? "transparent" : "white"};
border: ${props => props.transparent ? "none" : "thin solid #bfbfbf"};
display: flex;
flex-direction: ${props => props.direction || "column"};
align-items: center;
flex-direction: ${({direction}) => direction};
justify-content: space-between;
align-items: ${alignItems};
margin: 0.5em auto 0;
padding: 1em 20px;
max-width: 310px;
Expand All @@ -17,4 +24,8 @@ const Block = styled.div`
}
`

Block.defaultProps = {
direction: 'column',
}

export default Block
16 changes: 15 additions & 1 deletion frontend/src/components/atoms/Button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,25 @@ const Button = styled.button`
font-size: 1em;
margin: ${({ horizontal }) => horizontal ? "0 0.5em" : "0.5em auto 0"};
padding: 4px 15px;
width: 100%;
width: ${({ width }) => width};
max-width: 224px;
z-index: 1;
:disabled {
background-color: lightgrey;
color: grey;
cursor: default;
}
`

Button.defaultProps = {
width: '100%',
}

Button.propTypes = {
width: PropTypes.string.isRequired,
}

const LightButton = styled(Button)`
background: white;
color: black;
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/atoms/Graph/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const Wrapper = styled.div`
padding-top: 100%;
width: 100%;
position: relative;
z-index: -1;
`

const Content = styled.div`
Expand Down
24 changes: 16 additions & 8 deletions frontend/src/components/organisms/PaymentForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,35 @@ const TinyInput = styled(SimpleInput)`
margin: 0;
`

const Credit = ({ member: {membername}, index, ...props }) => (
const natural = value => value && Math.max(Math.round(value), 0)
const lessThan = x => (value => value && Math.min(natural(value), x))

const Credit = ({ total, member: {membername}, index, ...props }) => (
<TwoLineBlock
upper={<Label>{membername}</Label>}
lower={
<Field
name={`credits[${index}].amount`}
type="number"
parse={value => value && Number(value)}
normalize={lessThan(total)}
component={TinyInput}
/>
}
/>
)

const PaymentForm = ({ handleSubmit, room, members, payment, amountLeft, total, nBbang, ...props }) => {
const PaymentForm = ({ handleSubmit, room, members, payment, amountLeft, total, ...rest }) => {
const {
disabled,
set1OverN, setRandom, // setter callback
} = rest
return (
<Form onSubmit={handleSubmit}>
<Block>
<FieldWithLabel label="결제 내용" name="forWhat" type="text" component={SimpleInput} required />
<FieldWithLabel label="결제자" name="fromWho" component={Select} required>
<option selected value="">-- 멤버 목록 --</option>
<option value="">-- 멤버 목록 --</option>
{members.map(
({ membername }) => (
<option key={membername} value={membername}>
Expand All @@ -51,22 +59,22 @@ const PaymentForm = ({ handleSubmit, room, members, payment, amountLeft, total,
label="결제 금액"
name="total"
type="number"
parse={value => value && Number(value)}
normalize={natural}
required
component={SimpleInput}
/>
</Block>
<Block direction="row">
<Button type="button" onClick={() => nBbang(total, members)} light horizontal>N빵</Button>
<Button type="button" light horizontal>랜덤</Button>
<Button type="button" onClick={() => set1OverN(total, members)} light horizontal>N빵</Button>
<Button type="button" onClick={() => setRandom(total, members)} light horizontal>랜덤</Button>
<Button type="button" light horizontal>각자</Button>
</Block>
<Block>
남은 돈 ({amountLeft})
<hr />
{members.map(
(member, index) => (
<Credit key={index} index={index} member={member} />
<Credit key={index} index={index} member={member} total={total} />
)
)}
</Block>
Expand All @@ -78,7 +86,7 @@ const PaymentForm = ({ handleSubmit, room, members, payment, amountLeft, total,
>
취소
</LinkButton>
<Button type="submit" horizontal>확인</Button>
<Button type="submit" horizontal disabled={disabled}>확인</Button>
</Block>
</Form>
)
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/components/organisms/PaymentList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ const PaymentList = ({ paymentlist, roomurl }) => (
<List>
{
paymentlist && paymentlist.map(
({ forWhat, fromWho, total }, idx) => (
<ListItem key={idx} title={`${forWhat}${fromWho}`} description={total} linkTo={`/room/${roomurl}/payment_list/${forWhat}`} />
({ id, forWhat, fromWho, total }, idx) => (
<ListItem key={idx}
title={`${forWhat} - ${fromWho}`}
description={total}
linkTo={`/room/${roomurl}/payment/${id}/`}
/>
)
)
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/pages/IndividualPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ const IndividualPage = ({ sendlist, getlist, roomurl, nickname }) => (
<List>
{
getlist && getlist.map(
({ to, label }, idx) => (
<ListItem key={idx} title={to} description={label} />
({ from, label }, idx) => (
<ListItem key={idx} title={from} description={label} />
)
)
}
Expand Down
27 changes: 23 additions & 4 deletions frontend/src/components/pages/RoomPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,33 @@ const RoomPage = props => {
<Header />
<Block transparent>
<CopyToClipboard text={window.location.href} onCopy={() => {}}>
<Button>링크 복사</Button>
<Button width="auto" horizontal
style={{
'align-self': 'flex-end',
margin: '0 0 -2em'
}}
>
링크 복사
</Button>
</CopyToClipboard>
<Graph graph={graph} events={events} />
<SettingButton to={`/room/${room.url}/setting/`} />
</Block>
<Button onClick={onToggle}>
{showPayment ? "멤버 목록 보기" : "결제 목록 보기"}
</Button>
<Block direction="row" transparent
style={{margin: '0 auto', padding: '0'}}
>
<Button onClick={onToggle} width="auto" horizontal>
{showPayment ? "멤버 목록" : "결제 목록"}
</Button>
<h2 style={{
margin: '0 0.5em',
padding: '0 0.25em',
'border-bottom': 'solid',
color: 'dimgrey',
}}>
{room.roomname}
</h2>
</Block>
{showPayment ?
(<PaymentList />) :
(members && <MemberList />)
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/pages/UserPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom'

import { Block, Button, Header, List, ListItem } from 'components'
import { Block, Button, Header, List, LinkButton, ListItem } from 'components'

/**
* Presentational Components의 경우 redux 로직을 배제한다 (cf. pages/MainPage/index.js)
Expand All @@ -13,9 +13,9 @@ const UserPage = ({username, roomList, onClickUserInfo, onClickSignOut}) => (
<Header />
<Block transparent>
<h1>{username}</h1>
<Link to="/user/setting/">
<button onClick={onClickUserInfo}>유저 정보</button>
</Link>
<LinkButton to="/user/setting/" onClick={onClickUserInfo} width="auto">
유저 정보
</LinkButton>
</Block>
<Block>
새로운 방을 원한다면?
Expand Down
36 changes: 26 additions & 10 deletions frontend/src/containers/PaymentForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,41 @@ const mapStateToProps = state => ({
})

const mapDispatchToProps = dispatch => ({
nBbang(total, members) {
const amount = total / members.length
set1OverN(total, members) {
const amount = Math.floor(total / members.length)
members.forEach(
(m, index) =>
dispatch(change(FORM_NAME, `credits[${index}].amount`, amount))
)
}
},
setRandom(total, members) {
const rand = members.map(() => Math.random())
const sum = rand.reduce((a, b) => (a + b), 0)

rand.map(x => Math.floor(total * x / sum)).forEach(
(r, index) =>
dispatch(change(FORM_NAME, `credits[${index}].amount`, r))
)
},
})

const PaymentFormContainer = ({...props}) => {
const initialValues = {
credits: props.members.map(
({ membername }) => ({ toWho: membername, amount: 0.0 })
),
room: props.room,
}
const PaymentFormContainer = ({payment, ...props}) => {
const initialValues = (payment ?
{ // if payment exists
...payment,
room: props.room,
} :
{ // if payment doesn't exist
credits: props.members.map(
({ membername }) => ({ toWho: membername, amount: 0.0 })
),
room: props.room,
}
)

return (
<PaymentReduxForm
disabled={!!payment}
initialValues={initialValues}
{...props}
/>
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/containers/PaymentPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { connect } from 'react-redux'

import { PaymentPage } from 'components'

const PaymentPageContainer = props => {
return <PaymentPage {...props} />
const PaymentPageContainer = ({ match, payments, ...props }) => {
const paymentId = parseInt(match.params.payment_id)
const payment = payments.find(p => p.id === paymentId)
return <PaymentPage payment={payment} {...props} />
}

const mapStateToProps = state => ({
room: state.room.room,
members: state.member.members,
payment: state.payment.payment,
payments: state.payment.payments,
})

export default connect(mapStateToProps)(PaymentPageContainer)
Expand Down
11 changes: 10 additions & 1 deletion frontend/src/containers/RoomCreateForm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import { connect } from 'react-redux'
import { reduxForm, formValueSelector, arrayPush, change } from 'redux-form'
import { toastr } from 'react-redux-toastr'
import { reduxForm, formValueSelector, arrayPush, change, SubmissionError } from 'redux-form'
import { RoomCreateForm } from 'components'

import { roomCreateRequest } from 'store/actions'
Expand Down Expand Up @@ -33,6 +34,14 @@ export default connect(mapStateToProps, mapDispatchToProps)(
onSubmit(values, dispatch, props) {
const { roomname, members } = values
const { username, token } = props // username means ownername

if (!(members && members.length)) {
toastr.light(
"방 생성 오류", "화면 하단에서 다른 멤버를 최소 1명 추가해주세요.",
{ icon: 'error', status: 'error' }
)
return
}
dispatch(roomCreateRequest(roomname, members, username, token))
}
})(RoomCreateFormContainer)
Expand Down
10 changes: 3 additions & 7 deletions frontend/src/containers/RoomPage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import { Redirect } from 'react-router-dom'
import { push } from 'connected-react-router'
import { connect } from 'react-redux'
import { RoomPage } from 'components'

Expand All @@ -14,11 +14,7 @@ class RoomPageContainer extends React.Component {
}

render() {
const { room, member } = this.props

if (member) {
return <Redirect to={`/room/${room.url}/member/${member.id}/`} />
}
const { room, } = this.props

if (room) {
document.title = `${this.props.room.roomname} - Dutch Broomstick`
Expand All @@ -31,7 +27,6 @@ class RoomPageContainer extends React.Component {

const mapStateToProps = state => ({
room: state.room.room,
member: state.room.member,
members: state.member.members,
payments: state.payment.payments,
showPayment: state.room.showPayment,
Expand All @@ -42,6 +37,7 @@ const mapDispatchToProps = dispatch => ({
onLeave: () => dispatch(roomLeave()),
onClickMember: (member, sendlist, getlist) => {
dispatch(roomSetMember(member, sendlist, getlist))
dispatch(push(`member/${member.id}/`))
},
onToggle: () => dispatch(roomToggleContents()),
})
Expand Down
Loading

0 comments on commit 3096b5c

Please sign in to comment.