Upload User and Guild Icons
This commit is contained in:
parent
ab2ca97192
commit
9c86483235
@ -1,6 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { deleteGuild, updateGuild } from '../../../store/guilds';
|
||||
import { deleteGuild, updateGuild, uploadGuildIcon } from '../../../store/guilds';
|
||||
import { openSaveChanges } from '../../../store/ui';
|
||||
import NormalButton from '../../utils/buttons/normal-button';
|
||||
import Category from '../../utils/category';
|
||||
@ -37,11 +38,17 @@ const GuildSettingsOverview: React.FunctionComponent = () => {
|
||||
options={{ value: guild.name }}
|
||||
className="pt-5" />
|
||||
<Input
|
||||
label="Icon URL"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
label="Icon Image"
|
||||
name="iconURL"
|
||||
register={register}
|
||||
className="pt-5"
|
||||
register={(): any => {}}
|
||||
options={{ value: guild.iconURL }}
|
||||
className="pt-5" />
|
||||
onChange={(e) => {
|
||||
const file = e.currentTarget?.files?.[0];
|
||||
if (file) dispatch(uploadGuildIcon(guild.id, file));
|
||||
}} />
|
||||
</section>
|
||||
|
||||
<Category
|
||||
|
@ -3,7 +3,7 @@ import { useForm } from 'react-hook-form';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { toggleDevMode } from '../../../store/config';
|
||||
import { openSaveChanges } from '../../../store/ui';
|
||||
import { updateSelf, deleteSelf } from '../../../store/users';
|
||||
import { updateSelf, deleteSelf, uploadUserAvatar } from '../../../store/users';
|
||||
import NormalButton from '../../utils/buttons/normal-button';
|
||||
import Category from '../../utils/category';
|
||||
import Input from '../../utils/input/input';
|
||||
@ -33,31 +33,30 @@ const UserSettingsOverview: React.FunctionComponent = () => {
|
||||
</header>
|
||||
|
||||
<section className="w-1/2">
|
||||
<div className="pt-5">
|
||||
<Input
|
||||
label="Username"
|
||||
name="username"
|
||||
register={register}
|
||||
options={{ value: user.username }} />
|
||||
</div>
|
||||
|
||||
<div className="pt-5">
|
||||
<Input
|
||||
label="Email"
|
||||
name="email"
|
||||
register={register}
|
||||
options={{ value: user.email }} />
|
||||
</div>
|
||||
|
||||
<div className="pt-5">
|
||||
<Input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
label="Avatar Image"
|
||||
name="avatarURL"
|
||||
register={register}
|
||||
options={{ value: user.avatarURL }} />
|
||||
</div>
|
||||
<Input
|
||||
label="Username"
|
||||
name="username"
|
||||
register={register}
|
||||
options={{ value: user.username }}
|
||||
className="pt-5" />
|
||||
<Input
|
||||
label="Email"
|
||||
name="email"
|
||||
register={register}
|
||||
options={{ value: user.email }}
|
||||
className="pt-5" />
|
||||
<Input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
label="Avatar Image"
|
||||
className="pt-5"
|
||||
name="avatarURL"
|
||||
register={(): any => {}}
|
||||
options={{ value: user.avatarURL }}
|
||||
onChange={(e) => {
|
||||
const file = e.currentTarget?.files?.[0];
|
||||
if (file) dispatch(uploadUserAvatar(file));
|
||||
}} />
|
||||
</section>
|
||||
|
||||
<SaveChanges
|
||||
|
@ -22,4 +22,17 @@ export interface APIArgs {
|
||||
export interface WSArgs {
|
||||
data?: object;
|
||||
event: keyof WS.To;
|
||||
}
|
||||
|
||||
export const uploadFile = (file: File, callback?: (args: REST.From.Post['/upload']) => any) => (dispatch) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
dispatch(actions.restCallBegan({
|
||||
method: 'post',
|
||||
url: '/upload',
|
||||
data: formData,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
callback,
|
||||
}));
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import { WS } from '../types/ws';
|
||||
import { actions as api } from './api';
|
||||
import { actions as api, uploadFile } from './api';
|
||||
import { unique } from './utils/filter';
|
||||
|
||||
const slice = createSlice({
|
||||
@ -41,6 +41,12 @@ export const updateGuild = (guildId: string, payload: Partial<Entity.Guild>) =>
|
||||
}));
|
||||
}
|
||||
|
||||
export const uploadGuildIcon = (guildId: string, file: File) => (dispatch) => {
|
||||
const uploadCallback = async ({ url }: REST.From.Post['/upload']) =>
|
||||
dispatch(updateGuild(guildId, { iconURL: url }));
|
||||
dispatch(uploadFile(file, uploadCallback));
|
||||
}
|
||||
|
||||
export const deleteGuild = (guildId: string) => (dispatch) => {
|
||||
dispatch(api.wsCallBegan({
|
||||
event: 'GUILD_DELETE',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createSlice, createSelector } from '@reduxjs/toolkit';
|
||||
import { WS } from '../types/ws';
|
||||
import { actions as api } from './api';
|
||||
import { actions as api, uploadFile } from './api';
|
||||
import { unique } from './utils/filter';
|
||||
import { headers } from './utils/rest-headers';
|
||||
|
||||
@ -57,17 +57,9 @@ export const createMessage = (channelId: string, payload: Partial<Entity.Message
|
||||
|
||||
// each file is uploaded individually as a separate API call
|
||||
export const uploadFileAsMessage = (channelId: string, payload: Partial<Entity.Message>, file: File) => (dispatch) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
dispatch(api.restCallBegan({
|
||||
method: 'post',
|
||||
url: '/upload',
|
||||
data: formData,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
callback: async ({ url }: { url: string, hash: string }) =>
|
||||
dispatch(createMessage(channelId, payload, [url])),
|
||||
}));
|
||||
const uploadCallback = async ({ url }: REST.From.Post['/upload']) =>
|
||||
dispatch(createMessage(channelId, payload, [url]));
|
||||
dispatch(uploadFile(file, uploadCallback));
|
||||
}
|
||||
|
||||
export const updateMessage = (id: string, payload: Partial<Entity.Message>) => (dispatch) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createSlice, createSelector } from '@reduxjs/toolkit';
|
||||
import { WS } from '../types/ws';
|
||||
import { actions as api } from './api';
|
||||
import { actions as api, uploadFile } from './api';
|
||||
import { actions as meta } from './meta';
|
||||
import { unique } from './utils/filter';
|
||||
import { token } from './utils/rest-headers';
|
||||
@ -66,12 +66,18 @@ export const countUsers = () => (dispatch) => {
|
||||
}));
|
||||
}
|
||||
|
||||
export const uploadUserAvatar = (file: File) => (dispatch) => {
|
||||
const uploadCallback = async ({ url }: REST.From.Post['/upload']) =>
|
||||
dispatch(updateSelf({ avatarURL: url }));
|
||||
dispatch(uploadFile(file, uploadCallback));
|
||||
}
|
||||
|
||||
export const getUser = (id: string) =>
|
||||
createSelector<Store.AppState, Entity.User[], Entity.User>(
|
||||
state => state.entities.users,
|
||||
users => users.find(u => u.id === id) ?? {
|
||||
avatarURL: '/avatars/unknown.png',
|
||||
discriminator: 0,
|
||||
username: 'Unknown',
|
||||
avatarURL: '/avatars/unknown.png',
|
||||
} as Entity.User,
|
||||
);
|
6
types/rest.d.ts
vendored
6
types/rest.d.ts
vendored
@ -36,10 +36,8 @@ declare namespace REST {
|
||||
}
|
||||
}
|
||||
export interface Post {
|
||||
'/auth/change-password': {
|
||||
message: string;
|
||||
token: string;
|
||||
}
|
||||
'/upload': { url: string, hash: string };
|
||||
'/auth/change-password': { message: string, token: string }
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user