-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #36 from daodaoedu/feature/group-create
✨ create group page and form
- Loading branch information
Showing
18 changed files
with
675 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import Box from '@mui/material/Box'; | ||
import FormControlLabel from '@mui/material/FormControlLabel'; | ||
import Checkbox from '@mui/material/Checkbox'; | ||
import Select from './Select'; | ||
|
||
export default function AreaCheckbox({ | ||
options, | ||
itemLabel, | ||
itemValue, | ||
name, | ||
value, | ||
onChange, | ||
}) { | ||
return ( | ||
<> | ||
<Box sx={{ display: 'flex', label: { whiteSpace: 'nowrap' } }}> | ||
<FormControlLabel control={<Checkbox />} label="實體活動" /> | ||
<Select | ||
name={name} | ||
options={options} | ||
placeholder="地點" | ||
value={value} | ||
itemLabel={itemLabel} | ||
itemValue={itemValue} | ||
onChange={onChange} | ||
/> | ||
</Box> | ||
<div> | ||
<FormControlLabel control={<Checkbox />} label="線上" /> | ||
</div> | ||
<div> | ||
<FormControlLabel control={<Checkbox />} label="待討論" /> | ||
</div> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import FormControl from '@mui/material/FormControl'; | ||
import MuiSelect from '@mui/material/Select'; | ||
import MenuItem from '@mui/material/MenuItem'; | ||
|
||
export default function Select({ | ||
id, | ||
name, | ||
value, | ||
placeholder, | ||
options = [], | ||
itemLabel = 'label', | ||
fullWidth = true, | ||
multiple, | ||
onChange, | ||
sx, | ||
}) { | ||
const getValue = (any, key) => (typeof any === 'object' ? any[key] : any); | ||
const renderValue = (selected) => { | ||
if (selected.length === 0) return placeholder; | ||
if (Array.isArray(selected)) return selected.join('、'); | ||
return selected; | ||
}; | ||
|
||
return ( | ||
<FormControl size="small" fullWidth> | ||
<MuiSelect | ||
displayEmpty | ||
multiple={multiple} | ||
fullWidth={fullWidth} | ||
renderValue={renderValue} | ||
id={id} | ||
name={name} | ||
sx={{ | ||
color: value.length ? '#000' : '#92989A', | ||
'& legend': { display: 'none' }, | ||
'& fieldset': { top: 0 }, | ||
...sx, | ||
}} | ||
value={value} | ||
onChange={onChange} | ||
> | ||
{placeholder && ( | ||
<MenuItem disabled value="" sx={{ fontSize: 14 }}> | ||
{placeholder} | ||
</MenuItem> | ||
)} | ||
{options.map((item) => ( | ||
<MenuItem | ||
key={getValue(item, itemLabel)} | ||
value={getValue(item, itemLabel)} | ||
> | ||
{getValue(item, itemLabel)} | ||
</MenuItem> | ||
))} | ||
</MuiSelect> | ||
</FormControl> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { useState } from 'react'; | ||
import IconButton from '@mui/material/IconButton'; | ||
import FormHelperText from '@mui/material/FormHelperText'; | ||
import ClearIcon from '@mui/icons-material/Clear'; | ||
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; | ||
import { StyledChip, StyledTagsField } from '../Form.styled'; | ||
|
||
function TagsField({ label, helperText, ...props }) { | ||
const [tags, setTags] = useState([]); | ||
const [input, setInput] = useState(''); | ||
const [error, setError] = useState(''); | ||
|
||
const handleInput = (e) => { | ||
const { value } = e.target; | ||
if (value.length > 8) setError('標籤最多 8 個字'); | ||
else setError(''); | ||
setInput(value); | ||
}; | ||
|
||
const handleKeyDown = (e) => { | ||
if (error) return; | ||
const tag = input.trim(); | ||
if (e.key !== 'Enter' || !tag) return; | ||
if (tags.indexOf(tag) > -1) return; | ||
setTags((pre) => [...pre, tag]); | ||
setInput(''); | ||
}; | ||
|
||
const handleDelete = (tag) => () => { | ||
setTags((pre) => pre.filter((t) => t !== tag)); | ||
}; | ||
|
||
return ( | ||
<> | ||
<StyledTagsField> | ||
{tags.map((tag) => ( | ||
<StyledChip | ||
key={tag} | ||
label={tag} | ||
size="small" | ||
deleteIcon={<ClearIcon />} | ||
onDelete={handleDelete(tag)} | ||
/> | ||
))} | ||
{tags.length < 8 && ( | ||
<input | ||
{...props} | ||
value={input} | ||
onChange={handleInput} | ||
onKeyDown={handleKeyDown} | ||
/> | ||
)} | ||
{input.trim() && ( | ||
<IconButton sx={{ textTransform: 'none' }} size="small" edge="end"> | ||
<AddCircleOutlineIcon /> | ||
</IconButton> | ||
)} | ||
</StyledTagsField> | ||
<FormHelperText>{helperText}</FormHelperText> | ||
<span className="error-message">{error}</span> | ||
</> | ||
); | ||
} | ||
|
||
export default TagsField; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import MuiTextField from '@mui/material/TextField'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
export default function TextField({ | ||
id, | ||
placeholder, | ||
multiline, | ||
name, | ||
value, | ||
onChange, | ||
helperText, | ||
max, | ||
errorMessage, | ||
}) { | ||
const [error, setError] = useState(''); | ||
|
||
useEffect(() => { | ||
if (value.length > max) setError(errorMessage); | ||
else setError(''); | ||
}, [max, value]); | ||
|
||
return ( | ||
<> | ||
<MuiTextField | ||
fullWidth | ||
id={id} | ||
name={name} | ||
sx={{ '& legend': { display: 'none' } }} | ||
size="small" | ||
placeholder={placeholder} | ||
value={value} | ||
multiline={multiline} | ||
rows={multiline && 10} | ||
onChange={onChange} | ||
helperText={helperText} | ||
/> | ||
<span className="error-message">{error}</span> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { useRef, useState } from 'react'; | ||
import Box from '@mui/material/Box'; | ||
import Button from '@mui/material/Button'; | ||
import DeleteSvg from '@/public/assets/icons/delete.svg'; | ||
import { StyledUpload } from '../Form.styled'; | ||
import UploadSvg from './UploadSvg'; | ||
|
||
export default function Upload({ name, onChange }) { | ||
const [preview, setPreview] = useState(''); | ||
const [error, setError] = useState(''); | ||
const inputRef = useRef(); | ||
|
||
const changeHandler = (file) => { | ||
const event = { | ||
target: { | ||
name, | ||
value: file, | ||
}, | ||
}; | ||
onChange(event); | ||
}; | ||
|
||
const handleFile = (file) => { | ||
const imageType = /image.*/; | ||
setError(''); | ||
if (!file.type.match(imageType)) { | ||
setError('僅支援上傳圖片唷!'); | ||
return; | ||
} | ||
|
||
const reader = new FileReader(); | ||
reader.onload = (e) => setPreview(e.target.result); | ||
reader.readAsDataURL(file); | ||
changeHandler(file); | ||
}; | ||
|
||
const handleDragEnter = (e) => { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
}; | ||
|
||
const handleDragOver = (e) => { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
}; | ||
|
||
const handleDrop = (e) => { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
|
||
const { files } = e.dataTransfer; | ||
if (files?.[0]) handleFile(files[0]); | ||
}; | ||
|
||
const handleChange = (e) => { | ||
const { files } = e.target; | ||
if (files?.[0]) handleFile(files[0]); | ||
}; | ||
|
||
const handleClear = () => { | ||
setPreview(''); | ||
setError(''); | ||
inputRef.current.value = ''; | ||
changeHandler(null); | ||
}; | ||
|
||
return ( | ||
<Box sx={{ position: 'relative' }}> | ||
{preview && ( | ||
<Button | ||
variant="text" | ||
size="small" | ||
sx={{ | ||
position: 'absolute', | ||
right: 0, | ||
top: '-2rem', | ||
gap: 0.25, | ||
span: { | ||
marginTop: 0.25, | ||
}, | ||
}} | ||
onClick={handleClear} | ||
> | ||
<img src={DeleteSvg.src} alt="delete icon" /> | ||
<span>清除</span> | ||
</Button> | ||
)} | ||
<StyledUpload | ||
className={preview ? 'has-image' : ''} | ||
onClick={() => inputRef.current.click()} | ||
onDragEnter={handleDragEnter} | ||
onDragOver={handleDragOver} | ||
onDrop={handleDrop} | ||
> | ||
{preview && <img className="preview" src={preview} alt="預覽封面圖" />} | ||
<UploadSvg isActive={!!preview} /> | ||
<span>{preview ? '上傳其他圖片' : '點擊此處或將圖片拖曳至此'}</span> | ||
<input | ||
type="file" | ||
ref={inputRef} | ||
accept="image/*" | ||
onChange={handleChange} | ||
/> | ||
</StyledUpload> | ||
<span className="error-message">{error}</span> | ||
</Box> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export default function UploadSvg({ isActive }) { | ||
const fillColor = isActive ? '#FFFFFF' : '#89DAD7'; | ||
|
||
return ( | ||
<svg | ||
width="40" | ||
height="33" | ||
viewBox="0 0 40 33" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
d="M0 4.5C0 2.3 1.8 0.5 4 0.5H36C37.0609 0.5 38.0783 0.921427 38.8284 1.67157C39.5786 2.42172 40 3.43913 40 4.5V28.5C40 29.5609 39.5786 30.5783 38.8284 31.3284C38.0783 32.0786 37.0609 32.5 36 32.5H4C2.93913 32.5 1.92172 32.0786 1.17157 31.3284C0.421427 30.5783 0 29.5609 0 28.5V4.5ZM22 22.5L16 16.5L4 28.5H36L26 18.5L22 22.5ZM30 14.5C31.0609 14.5 32.0783 14.0786 32.8284 13.3284C33.5786 12.5783 34 11.5609 34 10.5C34 9.43913 33.5786 8.42172 32.8284 7.67157C32.0783 6.92143 31.0609 6.5 30 6.5C28.9391 6.5 27.9217 6.92143 27.1716 7.67157C26.4214 8.42172 26 9.43913 26 10.5C26 11.5609 26.4214 12.5783 27.1716 13.3284C27.9217 14.0786 28.9391 14.5 30 14.5Z" | ||
fill={fillColor} | ||
/> | ||
</svg> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import Tooltip from '@mui/material/Tooltip'; | ||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; | ||
import { StyledLabel, StyledGroup } from '../Form.styled'; | ||
|
||
const popperProps = { | ||
popper: { | ||
modifiers: [ | ||
{ | ||
name: 'offset', | ||
options: { | ||
offset: [0, -14], | ||
}, | ||
}, | ||
], | ||
}, | ||
}; | ||
|
||
export default function Wrapper({ id, required, label, children, tooltip }) { | ||
return ( | ||
<StyledGroup> | ||
<StyledLabel htmlFor={id} required={required}> | ||
{label} | ||
{tooltip && ( | ||
<Tooltip | ||
title={tooltip} | ||
slotProps={popperProps} | ||
placement="top" | ||
arrow | ||
> | ||
<InfoOutlinedIcon sx={{ width: 14, height: 14, mx: '4px' }} /> | ||
</Tooltip> | ||
)} | ||
</StyledLabel> | ||
{children} | ||
</StyledGroup> | ||
); | ||
} |
Oops, something went wrong.