Invite and Session API/Services; Home view; Sidebar Items; Modals
This commit is contained in:
parent
280158470a
commit
e36587b99d
80 changed files with 1343 additions and 71 deletions
|
|
@ -31,7 +31,7 @@ const updateChannelApi = async (
|
|||
const removeChannelApi = async (
|
||||
request: IRemoveChannelRequest,
|
||||
): Promise<IRemoveChannelResponse> => {
|
||||
return await callApi(HTTP.DELETE, `channel/${request.id}`, request);
|
||||
return await callApi(HTTP.DELETE, `channel/${request.id}`);
|
||||
};
|
||||
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ interface ICreateChannelResponse extends IFetchChannel {}
|
|||
interface IUpdateChannelRequest {
|
||||
id: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface IUpdateChannelResponse extends IFetchChannel {}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,20 @@ import { callApi, HTTP } from "../tools";
|
|||
import {
|
||||
IFetchCommunityRequest,
|
||||
IFetchCommunityResponse,
|
||||
ICreateCommunityRequest,
|
||||
ICreateCommunityResponse,
|
||||
IUpdateCommunityRequest,
|
||||
IUpdateCommunityResponse,
|
||||
IRemoveCommunityRequest,
|
||||
IRemoveCommunityResponse,
|
||||
IFetchCommunityChannelsRequest,
|
||||
IFetchCommunityChannelsResponse,
|
||||
IFetchCommunityRolesRequest,
|
||||
IFetchCommunityRolesResponse,
|
||||
IFetchCommunityMembersRequest,
|
||||
IFetchCommunityMembersResponse,
|
||||
IFetchCommunityInvitesRequest,
|
||||
IFetchCommunityInvitesResponse,
|
||||
} from "./types";
|
||||
|
||||
const fetchCommunityApi = async (
|
||||
|
|
@ -16,6 +24,24 @@ const fetchCommunityApi = async (
|
|||
return await callApi(HTTP.GET, `community/${request.id}`);
|
||||
};
|
||||
|
||||
const createCommunityApi = async (
|
||||
request: ICreateCommunityRequest,
|
||||
): Promise<ICreateCommunityResponse> => {
|
||||
return await callApi(HTTP.POST, `community`, request);
|
||||
};
|
||||
|
||||
const updateCommunityApi = async (
|
||||
request: IUpdateCommunityRequest,
|
||||
): Promise<IUpdateCommunityResponse> => {
|
||||
return await callApi(HTTP.PATCH, `community/${request.id}`, request);
|
||||
};
|
||||
|
||||
const removeCommunityApi = async (
|
||||
request: IRemoveCommunityRequest,
|
||||
): Promise<IRemoveCommunityResponse> => {
|
||||
return await callApi(HTTP.DELETE, `community/${request.id}`);
|
||||
};
|
||||
|
||||
const fetchCommunityChannelsApi = async (
|
||||
request: IFetchCommunityChannelsRequest,
|
||||
): Promise<IFetchCommunityChannelsResponse> => {
|
||||
|
|
@ -34,9 +60,19 @@ const fetchCommunityMembersApi = async (
|
|||
return await callApi(HTTP.GET, `community/${request.id}/members`);
|
||||
};
|
||||
|
||||
const fetchCommunityInvitesApi = async (
|
||||
request: IFetchCommunityInvitesRequest,
|
||||
): Promise<IFetchCommunityInvitesResponse> => {
|
||||
return await callApi(HTTP.GET, `community/${request.id}/invites`);
|
||||
};
|
||||
|
||||
export {
|
||||
fetchCommunityApi,
|
||||
createCommunityApi,
|
||||
updateCommunityApi,
|
||||
removeCommunityApi,
|
||||
fetchCommunityChannelsApi,
|
||||
fetchCommunityRolesApi,
|
||||
fetchCommunityMembersApi,
|
||||
fetchCommunityInvitesApi,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,28 @@ interface IFetchCommunityRequest {
|
|||
|
||||
interface IFetchCommunityResponse extends IFetchCommunity {}
|
||||
|
||||
interface ICreateCommunityRequest {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ICreateCommunityResponse extends IFetchCommunity {}
|
||||
|
||||
interface IUpdateCommunityRequest {
|
||||
id: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface IUpdateCommunityResponse extends IFetchCommunity {}
|
||||
|
||||
interface IRemoveCommunityRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IRemoveCommunityResponse {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityChannelsRequest {
|
||||
id: string;
|
||||
}
|
||||
|
|
@ -54,10 +76,29 @@ interface IFetchCommunityMember {
|
|||
username: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityInvitesRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityInvitesResponse {
|
||||
id: string;
|
||||
invites: IFetchCommunityInvite[];
|
||||
}
|
||||
|
||||
interface IFetchCommunityInvite {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IFetchCommunity,
|
||||
type IFetchCommunityRequest,
|
||||
type IFetchCommunityResponse,
|
||||
type ICreateCommunityRequest,
|
||||
type ICreateCommunityResponse,
|
||||
type IUpdateCommunityRequest,
|
||||
type IUpdateCommunityResponse,
|
||||
type IRemoveCommunityRequest,
|
||||
type IRemoveCommunityResponse,
|
||||
type IFetchCommunityChannelsRequest,
|
||||
type IFetchCommunityChannelsResponse,
|
||||
type IFetchCommunityChannel,
|
||||
|
|
@ -67,4 +108,7 @@ export {
|
|||
type IFetchCommunityMembersRequest,
|
||||
type IFetchCommunityMembersResponse,
|
||||
type IFetchCommunityMember,
|
||||
type IFetchCommunityInvitesRequest,
|
||||
type IFetchCommunityInvitesResponse,
|
||||
type IFetchCommunityInvite,
|
||||
};
|
||||
|
|
|
|||
2
src/api/invite/index.ts
Normal file
2
src/api/invite/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./invite";
|
||||
export * from "./types";
|
||||
29
src/api/invite/invite.ts
Normal file
29
src/api/invite/invite.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { callApi, HTTP } from "../tools";
|
||||
import {
|
||||
IFetchInviteRequest,
|
||||
IFetchInviteResponse,
|
||||
IRemoveInviteRequest,
|
||||
IRemoveInviteResponse,
|
||||
IAcceptInviteRequest,
|
||||
IAcceptInviteResponse,
|
||||
} from "./types";
|
||||
|
||||
const fetchInviteApi = async (
|
||||
request: IFetchInviteRequest,
|
||||
): Promise<IFetchInviteResponse> => {
|
||||
return await callApi(HTTP.GET, `invite/${request.id}`);
|
||||
};
|
||||
|
||||
const removeInviteApi = async (
|
||||
request: IRemoveInviteRequest,
|
||||
): Promise<IRemoveInviteResponse> => {
|
||||
return await callApi(HTTP.DELETE, `invite/${request.id}`);
|
||||
};
|
||||
|
||||
const acceptInviteApi = async (
|
||||
request: IAcceptInviteRequest,
|
||||
): Promise<IAcceptInviteResponse> => {
|
||||
return await callApi(HTTP.GET, `invite/${request.id}/accept`);
|
||||
};
|
||||
|
||||
export { fetchInviteApi, removeInviteApi, acceptInviteApi };
|
||||
48
src/api/invite/types.ts
Normal file
48
src/api/invite/types.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
interface IFetchInvite {
|
||||
id: string;
|
||||
communityId: string;
|
||||
valid: boolean;
|
||||
unlimitedInvites: boolean;
|
||||
hasExpiration: boolean;
|
||||
totalInvites: number;
|
||||
remainingInvites: number;
|
||||
creationDate: number;
|
||||
expirationDate: number;
|
||||
}
|
||||
|
||||
interface IFetchInviteRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchInviteResponse extends IFetchInvite {}
|
||||
|
||||
interface IRemoveInviteRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IRemoveInviteResponse {
|
||||
id: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
interface IAcceptInviteRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IAcceptInviteResponse {
|
||||
id: string;
|
||||
userId: string;
|
||||
userName: string;
|
||||
communityId: string;
|
||||
communityName: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IFetchInvite,
|
||||
type IFetchInviteRequest,
|
||||
type IFetchInviteResponse,
|
||||
type IRemoveInviteRequest,
|
||||
type IRemoveInviteResponse,
|
||||
type IAcceptInviteRequest,
|
||||
type IAcceptInviteResponse,
|
||||
};
|
||||
|
|
@ -31,7 +31,7 @@ const updateRoleApi = async (
|
|||
const removeRoleApi = async (
|
||||
request: IRemoveRoleRequest,
|
||||
): Promise<IRemoveRoleResponse> => {
|
||||
return await callApi(HTTP.DELETE, `role/${request.id}`, request);
|
||||
return await callApi(HTTP.DELETE, `role/${request.id}`);
|
||||
};
|
||||
|
||||
export { fetchRoleApi, createRoleApi, updateRoleApi, removeRoleApi };
|
||||
|
|
|
|||
2
src/api/session/index.ts
Normal file
2
src/api/session/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./session";
|
||||
export * from "./types";
|
||||
21
src/api/session/session.ts
Normal file
21
src/api/session/session.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { callApi, HTTP } from "../tools";
|
||||
import {
|
||||
IFetchSessionRequest,
|
||||
IFetchSessionResponse,
|
||||
IRemoveSessionRequest,
|
||||
IRemoveSessionResponse,
|
||||
} from "./types";
|
||||
|
||||
const fetchSessionApi = async (
|
||||
request: IFetchSessionRequest,
|
||||
): Promise<IFetchSessionResponse> => {
|
||||
return await callApi(HTTP.GET, `session/${request.id}`);
|
||||
};
|
||||
|
||||
const removeSessionApi = async (
|
||||
request: IRemoveSessionRequest,
|
||||
): Promise<IRemoveSessionResponse> => {
|
||||
return await callApi(HTTP.DELETE, `session/${request.id}`);
|
||||
};
|
||||
|
||||
export { fetchSessionApi, removeSessionApi };
|
||||
28
src/api/session/types.ts
Normal file
28
src/api/session/types.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
interface IFetchSession {
|
||||
id: string;
|
||||
userId: string;
|
||||
creationDate: number;
|
||||
}
|
||||
|
||||
interface IFetchSessionRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchSessionResponse extends IFetchSession {}
|
||||
|
||||
interface IRemoveSessionRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IRemoveSessionResponse {
|
||||
id: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IFetchSession,
|
||||
type IFetchSessionRequest,
|
||||
type IFetchSessionResponse,
|
||||
type IRemoveSessionRequest,
|
||||
type IRemoveSessionResponse,
|
||||
};
|
||||
|
|
@ -18,6 +18,20 @@ interface IFetchUserRequest {
|
|||
|
||||
interface IFetchUserResponse extends IFetchUser {}
|
||||
|
||||
interface IFetchUserSessionsRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchUserSessionsResponse {
|
||||
id: string;
|
||||
sessions: IFetchUserSession[];
|
||||
}
|
||||
|
||||
interface IFetchUserSession {
|
||||
id: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
interface IFetchUserCommunitiesRequest {
|
||||
id: string;
|
||||
}
|
||||
|
|
@ -30,7 +44,6 @@ interface IFetchUserCommunitiesResponse {
|
|||
interface IFetchUserCommunity {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
@ -38,6 +51,9 @@ export {
|
|||
type IFetchLoggedUserResponse,
|
||||
type IFetchUserRequest,
|
||||
type IFetchUserResponse,
|
||||
type IFetchUserSessionsRequest,
|
||||
type IFetchUserSessionsResponse,
|
||||
type IFetchUserSession,
|
||||
type IFetchUserCommunitiesRequest,
|
||||
type IFetchUserCommunitiesResponse,
|
||||
type IFetchUserCommunity,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import {
|
|||
IFetchLoggedUserResponse,
|
||||
IFetchUserRequest,
|
||||
IFetchUserResponse,
|
||||
IFetchUserSessionsRequest,
|
||||
IFetchUserSessionsResponse,
|
||||
IFetchUserCommunitiesRequest,
|
||||
IFetchUserCommunitiesResponse,
|
||||
} from "./types";
|
||||
|
|
@ -17,10 +19,21 @@ const fetchUserApi = async (
|
|||
return await callApi(HTTP.GET, `user/${request.id}`);
|
||||
};
|
||||
|
||||
const fetchUserSessionsApi = async (
|
||||
request: IFetchUserSessionsRequest,
|
||||
): Promise<IFetchUserSessionsResponse> => {
|
||||
return await callApi(HTTP.GET, `user/${request.id}/sessions`);
|
||||
};
|
||||
|
||||
const fetchUserCommunitiesApi = async (
|
||||
request: IFetchUserCommunitiesRequest,
|
||||
): Promise<IFetchUserCommunitiesResponse> => {
|
||||
return await callApi(HTTP.GET, `user/${request.id}/communities`);
|
||||
};
|
||||
|
||||
export { fetchLoggedUserApi, fetchUserApi, fetchUserCommunitiesApi };
|
||||
export {
|
||||
fetchLoggedUserApi,
|
||||
fetchUserApi,
|
||||
fetchUserSessionsApi,
|
||||
fetchUserCommunitiesApi,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const Channel: Component<IChannelProps> = (props: IChannelProps) => {
|
|||
return (
|
||||
<li
|
||||
class={`flex flex-row gap-2 items-center p-1 cursor-pointer rounded-lg ${props.active ? "bg-stone-700 hover:bg-stone-700" : "hover:bg-stone-800"}`}
|
||||
onClick={() => props.onChannelClick(props.id)}
|
||||
onClick={() => props.onChannelClick?.(props.id)}
|
||||
>
|
||||
<div class="font-bold text-xl"> #</div>
|
||||
<div class="font-bold">{props.name}</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ interface IChannelProps {
|
|||
id: string;
|
||||
name: string;
|
||||
active: boolean;
|
||||
onChannelClick: (id: string) => void;
|
||||
onChannelClick?: (id: string) => void;
|
||||
}
|
||||
|
||||
export { type IChannelProps };
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ const Community: Component<ICommunityProps> = (props: ICommunityProps) => {
|
|||
return (
|
||||
<div
|
||||
class="avatar cursor-pointer"
|
||||
onClick={() => props.onCommunityClick(props.id)}
|
||||
onClick={() => props.onCommunityClick?.(props.id)}
|
||||
>
|
||||
<div
|
||||
class={`w-full transition-[border-radius] duration-300 outline-stone-300 hover:outline-2 ${props.active ? "rounded-lg outline-2" : "rounded-4xl"}`}
|
||||
class={`w-full transition-[border-radius] duration-300 outline-stone-300 ${props.active ? "rounded-lg outline-3 hover:outline-3" : "rounded-4xl hover:outline-2"}`}
|
||||
>
|
||||
<img src={props.avatar} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ interface ICommunityProps {
|
|||
name: string;
|
||||
avatar: string;
|
||||
active: boolean;
|
||||
onCommunityClick: (id: string) => void;
|
||||
onCommunityClick?: (id: string) => void;
|
||||
}
|
||||
|
||||
export { type ICommunityProps };
|
||||
|
|
|
|||
101
src/components/CommunityModal/CommunityModal.tsx
Normal file
101
src/components/CommunityModal/CommunityModal.tsx
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import { createSignal, type Component } from "solid-js";
|
||||
import { ICommunityModalProps } from "./types";
|
||||
import { dispatch } from "../../store/state";
|
||||
import { CommunityActionTypes } from "../../store/community";
|
||||
import { InviteActionTypes } from "../../store/invite";
|
||||
|
||||
const CommunityModal: Component<ICommunityModalProps> = (props) => {
|
||||
const [getCommunityName, setCommunityName] = createSignal<string>("");
|
||||
const [getInviteId, setInviteId] = createSignal<string>("");
|
||||
|
||||
const onCreateCommunity = () => {
|
||||
dispatch({
|
||||
type: CommunityActionTypes.CREATE_COMMUNITY_START,
|
||||
payload: {
|
||||
name: getCommunityName(),
|
||||
},
|
||||
});
|
||||
|
||||
setCommunityName("");
|
||||
|
||||
props.onClose?.();
|
||||
};
|
||||
|
||||
const onJoinCommunity = () => {
|
||||
dispatch({
|
||||
type: InviteActionTypes.ACCEPT_INVITE_START,
|
||||
payload: getInviteId(),
|
||||
});
|
||||
|
||||
setInviteId("");
|
||||
|
||||
props.onClose?.();
|
||||
};
|
||||
|
||||
const createCommunityHtml = () => (
|
||||
<>
|
||||
<h3 class="text-lg font-bold text-center mb-6">
|
||||
Create a new Community
|
||||
</h3>
|
||||
<div class="bg-stone-800 h-16 p-2 flex flex-row gap-2 rounded-2xl">
|
||||
<label class="bg-stone-800 input w-full h-full rounded-xl focus:border-none outline-none">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter name of the new community"
|
||||
value={getCommunityName()}
|
||||
onInput={(e) => setCommunityName(e.currentTarget.value)}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
class="bg-stone-950 btn btn-neutral h-full rounded-xl"
|
||||
onClick={onCreateCommunity}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
const joinCommunityHtml = () => (
|
||||
<>
|
||||
<h3 class="text-lg font-bold text-center mb-6">
|
||||
Join an existing Community
|
||||
</h3>
|
||||
<div class="bg-stone-800 h-16 p-2 flex flex-row gap-2 rounded-2xl">
|
||||
<label class="bg-stone-800 input w-full h-full rounded-xl focus:border-none outline-none">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter invite ID"
|
||||
value={getInviteId()}
|
||||
onInput={(e) => setInviteId(e.currentTarget.value)}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
class="bg-stone-950 btn btn-neutral h-full rounded-xl"
|
||||
onClick={onJoinCommunity}
|
||||
>
|
||||
Join
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<dialog ref={props.dialogRef} class="modal bg-[#00000050]">
|
||||
<div class="modal-box bg-stone-950 rounded-3xl">
|
||||
{createCommunityHtml()}
|
||||
<div class="divider my-8"></div>
|
||||
{joinCommunityHtml()}
|
||||
</div>
|
||||
<form
|
||||
onClick={props.onClose}
|
||||
method="dialog"
|
||||
class="modal-backdrop"
|
||||
></form>
|
||||
</dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommunityModal;
|
||||
2
src/components/CommunityModal/index.ts
Normal file
2
src/components/CommunityModal/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./CommunityModal";
|
||||
export * from "./types";
|
||||
6
src/components/CommunityModal/types.ts
Normal file
6
src/components/CommunityModal/types.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
interface ICommunityModalProps {
|
||||
dialogRef?: (element: HTMLDialogElement) => void;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export { type ICommunityModalProps };
|
||||
22
src/components/HomeCard/HomeCard.tsx
Normal file
22
src/components/HomeCard/HomeCard.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { IHomeCardProps } from "./types";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
|
||||
const HomeCard: Component<IHomeCardProps> = (props: IHomeCardProps) => {
|
||||
return (
|
||||
<a class="w-60 cursor-pointer" onClick={props.onClick}>
|
||||
<div class="card border-2 bg-stone-800 border-stone-500 hover:border-stone-100 w-60 h-60">
|
||||
<div class="flex flex-col h-full gap-1 m-6">
|
||||
<div class="w-20">
|
||||
<Dynamic component={props.icon} />
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<h2 class="card-title">{props.title}</h2>
|
||||
<p>{props.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export { HomeCard };
|
||||
2
src/components/HomeCard/index.ts
Normal file
2
src/components/HomeCard/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./HomeCard";
|
||||
export * from "./types";
|
||||
11
src/components/HomeCard/types.ts
Normal file
11
src/components/HomeCard/types.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { JSXElement } from "solid-js";
|
||||
import { IconParameters } from "../icons";
|
||||
|
||||
interface IHomeCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
onClick?: () => void;
|
||||
icon: (props: IconParameters) => JSXElement;
|
||||
}
|
||||
|
||||
export { type IHomeCardProps };
|
||||
|
|
@ -5,7 +5,7 @@ const Member: Component<IMemberProps> = (props: IMemberProps) => {
|
|||
return (
|
||||
<li
|
||||
class={`flex flex-row gap-4 items-center p-1 cursor-pointer rounded-lg ${props.active ? "bg-stone-700 hover:bg-stone-700" : "hover:bg-stone-800"}`}
|
||||
onClick={() => props.onMemberClick(props.id)}
|
||||
onClick={() => props.onMemberClick?.(props.id)}
|
||||
>
|
||||
<div class="avatar">
|
||||
<div class="w-9 rounded-full">
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ interface IMemberProps {
|
|||
username: string;
|
||||
avatar: string;
|
||||
active: boolean;
|
||||
onMemberClick: (id: string) => void;
|
||||
onMemberClick?: (id: string) => void;
|
||||
}
|
||||
|
||||
export { type IMemberProps };
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const Message: Component<IMessageProps> = (props: IMessageProps) => {
|
|||
<li class="list-row p-3 hover:bg-stone-700">
|
||||
<div
|
||||
class="avatar cursor-pointer"
|
||||
onClick={() => props.onProfileClick(props.userId)}
|
||||
onClick={() => props.onProfileClick?.(props.userId)}
|
||||
>
|
||||
<div class="w-10 rounded-full">
|
||||
<img src={props.avatar} />
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ interface IMessageProps {
|
|||
userId: string;
|
||||
username: string;
|
||||
avatar: string;
|
||||
onProfileClick: (userId: string) => void;
|
||||
onProfileClick?: (userId: string) => void;
|
||||
}
|
||||
|
||||
export { type IMessageProps };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { state } from "../../store/state";
|
||||
|
||||
const MessageBar: Component = () => {
|
||||
return (
|
||||
|
|
@ -8,7 +7,7 @@ const MessageBar: Component = () => {
|
|||
<label class="bg-stone-800/50 backdrop-blur-lg input w-full h-full rounded-full focus:border-none outline-none">
|
||||
<input type="text" placeholder="Send a message..." />
|
||||
</label>
|
||||
<button class="bg-black/50 backdrop-blur-lg btn btn-neutral h-full rounded-full">
|
||||
<button class="bg-stone-950/50 backdrop-blur-lg btn btn-neutral h-full rounded-full">
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
22
src/components/SettingsModal/SettingsModal.tsx
Normal file
22
src/components/SettingsModal/SettingsModal.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { ISettingsModalProps } from "./types";
|
||||
|
||||
const SettingsModal: Component<ISettingsModalProps> = (props) => {
|
||||
return (
|
||||
<div>
|
||||
<dialog ref={props.dialogRef} class="modal bg-[#00000050]">
|
||||
<div class="modal-box bg-stone-950 rounded-3xl">
|
||||
<h3 class="text-lg font-bold text-center">Settings</h3>
|
||||
<p class="py-4 text-center">Not implemented yet</p>
|
||||
</div>
|
||||
<form
|
||||
onClick={props.onClose}
|
||||
method="dialog"
|
||||
class="modal-backdrop"
|
||||
></form>
|
||||
</dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsModal;
|
||||
2
src/components/SettingsModal/index.ts
Normal file
2
src/components/SettingsModal/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./SettingsModal";
|
||||
export * from "./types";
|
||||
6
src/components/SettingsModal/types.ts
Normal file
6
src/components/SettingsModal/types.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
interface ISettingsModalProps {
|
||||
dialogRef?: (element: HTMLDialogElement) => void;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export { type ISettingsModalProps };
|
||||
18
src/components/SidebarItem/SidebarItem.tsx
Normal file
18
src/components/SidebarItem/SidebarItem.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { ISidebarItemProps } from "./types";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
|
||||
const SidebarItem: Component<ISidebarItemProps> = (
|
||||
props: ISidebarItemProps,
|
||||
) => {
|
||||
return (
|
||||
<div
|
||||
class={`bg-stone-800 w-full p-2 cursor-pointer transition-[border-radius] duration-300 outline-stone-300 ${props.active ? "rounded-lg outline-3 hover:outline-3" : "rounded-4xl hover:outline-2"}`}
|
||||
onClick={() => props.onClick?.()}
|
||||
>
|
||||
<Dynamic component={props.icon} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { SidebarItem };
|
||||
2
src/components/SidebarItem/index.ts
Normal file
2
src/components/SidebarItem/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./SidebarItem";
|
||||
export * from "./types";
|
||||
10
src/components/SidebarItem/types.ts
Normal file
10
src/components/SidebarItem/types.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { JSXElement } from "solid-js";
|
||||
import { IconParameters } from "../icons";
|
||||
|
||||
interface ISidebarItemProps {
|
||||
icon: (props: IconParameters) => JSXElement;
|
||||
active: boolean;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export { type ISidebarItemProps };
|
||||
28
src/components/icons/HomeIcon.tsx
Normal file
28
src/components/icons/HomeIcon.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import type { Component } from "solid-js";
|
||||
|
||||
import { IconParameters, defaultFillIconParameters as defaults } from "./types";
|
||||
|
||||
const HomeIcon: Component<IconParameters> = ({
|
||||
width,
|
||||
height,
|
||||
fill = defaults.fill,
|
||||
stroke = defaults.stroke,
|
||||
strokeWidth = defaults.strokeWidth,
|
||||
}: IconParameters) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={width}
|
||||
height={height}
|
||||
fill={fill}
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width={strokeWidth}
|
||||
stroke={stroke}
|
||||
>
|
||||
<path d="M11.47 3.841a.75.75 0 0 1 1.06 0l8.69 8.69a.75.75 0 1 0 1.06-1.061l-8.689-8.69a2.25 2.25 0 0 0-3.182 0l-8.69 8.69a.75.75 0 1 0 1.061 1.06l8.69-8.689Z" />
|
||||
<path d="m12 5.432 8.159 8.159c.03.03.06.058.091.086v6.198c0 1.035-.84 1.875-1.875 1.875H15a.75.75 0 0 1-.75-.75v-4.5a.75.75 0 0 0-.75-.75h-3a.75.75 0 0 0-.75.75V21a.75.75 0 0 1-.75.75H5.625a1.875 1.875 0 0 1-1.875-1.875v-6.198a2.29 2.29 0 0 0 .091-.086L12 5.432Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomeIcon;
|
||||
31
src/components/icons/PlusIcon.tsx
Normal file
31
src/components/icons/PlusIcon.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import type { Component } from "solid-js";
|
||||
|
||||
import { IconParameters, defaultFillIconParameters as defaults } from "./types";
|
||||
|
||||
const PlusIcon: Component<IconParameters> = ({
|
||||
width,
|
||||
height,
|
||||
fill = defaults.fill,
|
||||
stroke = defaults.stroke,
|
||||
strokeWidth = defaults.strokeWidth,
|
||||
}: IconParameters) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={width}
|
||||
height={height}
|
||||
fill={fill}
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width={strokeWidth}
|
||||
stroke={stroke}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12 3.75a.75.75 0 0 1 .75.75v6.75h6.75a.75.75 0 0 1 0 1.5h-6.75v6.75a.75.75 0 0 1-1.5 0v-6.75H4.5a.75.75 0 0 1 0-1.5h6.75V4.5a.75.75 0 0 1 .75-.75Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlusIcon;
|
||||
31
src/components/icons/SettingsIcon.tsx
Normal file
31
src/components/icons/SettingsIcon.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import type { Component } from "solid-js";
|
||||
|
||||
import { IconParameters, defaultFillIconParameters as defaults } from "./types";
|
||||
|
||||
const SettingsIcon: Component<IconParameters> = ({
|
||||
width,
|
||||
height,
|
||||
fill = defaults.fill,
|
||||
stroke = defaults.stroke,
|
||||
strokeWidth = defaults.strokeWidth,
|
||||
}: IconParameters) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={width}
|
||||
height={height}
|
||||
fill={fill}
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width={strokeWidth}
|
||||
stroke={stroke}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M11.078 2.25c-.917 0-1.699.663-1.85 1.567L9.05 4.889c-.02.12-.115.26-.297.348a7.493 7.493 0 0 0-.986.57c-.166.115-.334.126-.45.083L6.3 5.508a1.875 1.875 0 0 0-2.282.819l-.922 1.597a1.875 1.875 0 0 0 .432 2.385l.84.692c.095.078.17.229.154.43a7.598 7.598 0 0 0 0 1.139c.015.2-.059.352-.153.43l-.841.692a1.875 1.875 0 0 0-.432 2.385l.922 1.597a1.875 1.875 0 0 0 2.282.818l1.019-.382c.115-.043.283-.031.45.082.312.214.641.405.985.57.182.088.277.228.297.35l.178 1.071c.151.904.933 1.567 1.85 1.567h1.844c.916 0 1.699-.663 1.85-1.567l.178-1.072c.02-.12.114-.26.297-.349.344-.165.673-.356.985-.57.167-.114.335-.125.45-.082l1.02.382a1.875 1.875 0 0 0 2.28-.819l.923-1.597a1.875 1.875 0 0 0-.432-2.385l-.84-.692c-.095-.078-.17-.229-.154-.43a7.614 7.614 0 0 0 0-1.139c-.016-.2.059-.352.153-.43l.84-.692c.708-.582.891-1.59.433-2.385l-.922-1.597a1.875 1.875 0 0 0-2.282-.818l-1.02.382c-.114.043-.282.031-.449-.083a7.49 7.49 0 0 0-.985-.57c-.183-.087-.277-.227-.297-.348l-.179-1.072a1.875 1.875 0 0 0-1.85-1.567h-1.843ZM12 15.75a3.75 3.75 0 1 0 0-7.5 3.75 3.75 0 0 0 0 7.5Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsIcon;
|
||||
7
src/components/icons/index.ts
Normal file
7
src/components/icons/index.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import HomeIcon from "./HomeIcon";
|
||||
import SettingsIcon from "./SettingsIcon";
|
||||
import PlusIcon from "./PlusIcon";
|
||||
|
||||
import type { IconParameters } from "./types";
|
||||
|
||||
export { IconParameters, HomeIcon, SettingsIcon, PlusIcon };
|
||||
26
src/components/icons/types.ts
Normal file
26
src/components/icons/types.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
interface IconParameters {
|
||||
width?: number
|
||||
height?: number
|
||||
fill?: string
|
||||
stroke?: string
|
||||
strokeWidth?: number
|
||||
}
|
||||
|
||||
const defaultFillIconParameters: IconParameters = {
|
||||
width: 24,
|
||||
height: 24,
|
||||
fill: 'currentColor',
|
||||
stroke: 'none',
|
||||
strokeWidth: 0,
|
||||
}
|
||||
|
||||
const defaultStrokeIconParameters: IconParameters = {
|
||||
width: 24,
|
||||
height: 24,
|
||||
fill: 'none',
|
||||
stroke: 'currentColor',
|
||||
strokeWidth: 1.5,
|
||||
}
|
||||
|
||||
export type { IconParameters }
|
||||
export { defaultFillIconParameters, defaultStrokeIconParameters }
|
||||
|
|
@ -30,10 +30,15 @@ const createChannel = async (name: string, communityId: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
const updateChannel = async (id: string, name?: string) => {
|
||||
const updateChannel = async (
|
||||
id: string,
|
||||
name?: string,
|
||||
description?: string,
|
||||
) => {
|
||||
const data = await updateChannelApi({
|
||||
id: id,
|
||||
name: name,
|
||||
description: description,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
import {
|
||||
fetchCommunityApi,
|
||||
createCommunityApi,
|
||||
updateCommunityApi,
|
||||
removeCommunityApi,
|
||||
fetchCommunityChannelsApi,
|
||||
fetchCommunityRolesApi,
|
||||
fetchCommunityMembersApi,
|
||||
fetchCommunityInvitesApi,
|
||||
} from "../../api/community";
|
||||
import { CommunityActionTypes } from "../../store/community";
|
||||
import { ChannelActionTypes } from "../../store/channel";
|
||||
import { RoleActionTypes } from "../../store/role";
|
||||
import { UserActionTypes } from "../../store/user";
|
||||
import { dispatch } from "../../store/state";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { InviteActionTypes } from "../../store/invite";
|
||||
|
||||
const fetchCommunity = async (id: string) => {
|
||||
const data = await fetchCommunityApi({
|
||||
|
|
@ -21,6 +26,66 @@ const fetchCommunity = async (id: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
const createCommunity = async (name: string) => {
|
||||
const data = await createCommunityApi({
|
||||
name: name,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.CREATE_COMMUNITY_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
if (state.user.loggedUserId) {
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_COMMUNITIES_START,
|
||||
payload: state.user.loggedUserId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const updateCommunity = async (
|
||||
id: string,
|
||||
name?: string,
|
||||
description?: string,
|
||||
) => {
|
||||
const data = await updateCommunityApi({
|
||||
id: id,
|
||||
name: name,
|
||||
description: description,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.UPDATE_COMMUNITY_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
if (state.user.loggedUserId) {
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_COMMUNITIES_START,
|
||||
payload: state.user.loggedUserId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const removeCommunity = async (id: string) => {
|
||||
const data = await removeCommunityApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.REMOVE_COMMUNITY_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
if (state.user.loggedUserId) {
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_COMMUNITIES_START,
|
||||
payload: state.user.loggedUserId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const fetchCommunityChannels = async (id: string) => {
|
||||
const data = await fetchCommunityChannelsApi({
|
||||
id: id,
|
||||
|
|
@ -75,9 +140,31 @@ const fetchCommunityMembers = async (id: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
const fetchCommunityInvites = async (id: string) => {
|
||||
const data = await fetchCommunityInvitesApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_INVITES_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
data.invites.forEach((invite) => {
|
||||
dispatch({
|
||||
type: InviteActionTypes.SET_INVITE,
|
||||
payload: invite,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
fetchCommunity,
|
||||
createCommunity,
|
||||
updateCommunity,
|
||||
removeCommunity,
|
||||
fetchCommunityChannels,
|
||||
fetchCommunityRoles,
|
||||
fetchCommunityMembers,
|
||||
fetchCommunityInvites,
|
||||
};
|
||||
|
|
|
|||
1
src/services/invite/index.ts
Normal file
1
src/services/invite/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./invite";
|
||||
50
src/services/invite/invite.ts
Normal file
50
src/services/invite/invite.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import {
|
||||
fetchInviteApi,
|
||||
removeInviteApi,
|
||||
acceptInviteApi,
|
||||
} from "../../api/invite";
|
||||
import { InviteActionTypes } from "../../store/invite";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { UserActionTypes } from "../../store/user";
|
||||
|
||||
const fetchInvite = async (id: string) => {
|
||||
const data = await fetchInviteApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: InviteActionTypes.FETCH_INVITE_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
};
|
||||
|
||||
const removeInvite = async (id: string) => {
|
||||
const data = await removeInviteApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: InviteActionTypes.REMOVE_INVITE_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
};
|
||||
|
||||
const acceptInvite = async (id: string) => {
|
||||
const data = await acceptInviteApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: InviteActionTypes.ACCEPT_INVITE_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
if (state.user.loggedUserId) {
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_COMMUNITIES_START,
|
||||
payload: state.user.loggedUserId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { fetchInvite, removeInvite, acceptInvite };
|
||||
1
src/services/session/index.ts
Normal file
1
src/services/session/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./session";
|
||||
27
src/services/session/session.ts
Normal file
27
src/services/session/session.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { fetchSessionApi, removeSessionApi } from "../../api/session";
|
||||
import { SessionActionTypes } from "../../store/session";
|
||||
import { dispatch } from "../../store/state";
|
||||
|
||||
const fetchSession = async (id: string) => {
|
||||
const data = await fetchSessionApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: SessionActionTypes.FETCH_SESSION_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
};
|
||||
|
||||
const removeSession = async (id: string) => {
|
||||
const data = await removeSessionApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: SessionActionTypes.REMOVE_SESSION_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
};
|
||||
|
||||
export { fetchSession, removeSession };
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
import {
|
||||
fetchLoggedUserApi,
|
||||
fetchUserApi,
|
||||
fetchUserSessionsApi,
|
||||
fetchUserCommunitiesApi,
|
||||
} from "../../api/user";
|
||||
import { UserActionTypes } from "../../store/user";
|
||||
import { CommunityActionTypes } from "../../store/community";
|
||||
import { dispatch } from "../../store/state";
|
||||
import { SessionActionTypes } from "../../store/session";
|
||||
|
||||
const fetchLoggedUser = async () => {
|
||||
const data = await fetchLoggedUserApi();
|
||||
|
|
@ -27,6 +29,24 @@ const fetchUser = async (id: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
const fetchUserSessions = async (id: string) => {
|
||||
const data = await fetchUserSessionsApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_SESSIONS_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
data.sessions.forEach((session) => {
|
||||
dispatch({
|
||||
type: SessionActionTypes.SET_SESSION,
|
||||
payload: session,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const fetchUserCommunities = async (id: string) => {
|
||||
const data = await fetchUserCommunitiesApi({
|
||||
id: id,
|
||||
|
|
@ -45,4 +65,4 @@ const fetchUserCommunities = async (id: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
export { fetchLoggedUser, fetchUser, fetchUserCommunities };
|
||||
export { fetchLoggedUser, fetchUser, fetchUserSessions, fetchUserCommunities };
|
||||
|
|
|
|||
|
|
@ -1,21 +1,30 @@
|
|||
import { AppActionTypes, AppAction } from "./app";
|
||||
import { AuthActionTypes, AuthAction } from "./auth";
|
||||
import { UserActionTypes, UserAction } from "./user";
|
||||
import { CommunityActionTypes, CommunityAction } from "./community";
|
||||
import { ChannelActionTypes, ChannelAction } from "./channel";
|
||||
import { RoleActionTypes, RoleAction } from "./role";
|
||||
import { SessionActionTypes, SessionAction } from "./session";
|
||||
import { InviteActionTypes, InviteAction } from "./invite";
|
||||
|
||||
type ActionTypes =
|
||||
| AppActionTypes
|
||||
| AuthActionTypes
|
||||
| UserActionTypes
|
||||
| CommunityActionTypes
|
||||
| ChannelActionTypes
|
||||
| RoleActionTypes;
|
||||
| RoleActionTypes
|
||||
| SessionActionTypes
|
||||
| InviteActionTypes;
|
||||
|
||||
type Action =
|
||||
| AppAction
|
||||
| AuthAction
|
||||
| UserAction
|
||||
| CommunityAction
|
||||
| ChannelAction
|
||||
| RoleAction;
|
||||
| RoleAction
|
||||
| SessionAction
|
||||
| InviteAction;
|
||||
|
||||
export { type Action, type ActionTypes };
|
||||
|
|
|
|||
12
src/store/app/actions.ts
Normal file
12
src/store/app/actions.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
enum AppActionTypes {
|
||||
SET_HOME_OPEN = "SET_HOME_OPEN",
|
||||
SET_SETTINGS_OPEN = "SET_SETTINGS_OPEN",
|
||||
SET_ADD_COMMUNITY_OPEN = "SET_ADD_COMMUNITY_OPEN",
|
||||
}
|
||||
|
||||
type AppAction =
|
||||
| { type: AppActionTypes.SET_HOME_OPEN; payload: boolean }
|
||||
| { type: AppActionTypes.SET_SETTINGS_OPEN; payload: boolean }
|
||||
| { type: AppActionTypes.SET_ADD_COMMUNITY_OPEN; payload: boolean };
|
||||
|
||||
export { AppActionTypes, type AppAction };
|
||||
21
src/store/app/app.ts
Normal file
21
src/store/app/app.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { setState } from "../state";
|
||||
import { AppActionTypes, AppAction } from "./actions";
|
||||
import { IAppState } from "./types";
|
||||
|
||||
function appReducer(_state: IAppState, action: AppAction) {
|
||||
switch (action.type) {
|
||||
case AppActionTypes.SET_HOME_OPEN:
|
||||
setState("app", "homeOpen", action.payload);
|
||||
break;
|
||||
case AppActionTypes.SET_SETTINGS_OPEN:
|
||||
setState("app", "dialogsOpen", "settingsOpen", false);
|
||||
setState("app", "dialogsOpen", "settingsOpen", action.payload);
|
||||
break;
|
||||
case AppActionTypes.SET_ADD_COMMUNITY_OPEN:
|
||||
setState("app", "dialogsOpen", "addCommunityOpen", false);
|
||||
setState("app", "dialogsOpen", "addCommunityOpen", action.payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export { appReducer };
|
||||
3
src/store/app/index.ts
Normal file
3
src/store/app/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./app";
|
||||
export * from "./actions";
|
||||
export * from "./types";
|
||||
11
src/store/app/types.ts
Normal file
11
src/store/app/types.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
interface IAppState {
|
||||
homeOpen: boolean;
|
||||
dialogsOpen: IDialogsOpen;
|
||||
}
|
||||
|
||||
interface IDialogsOpen {
|
||||
settingsOpen: boolean;
|
||||
addCommunityOpen: boolean;
|
||||
}
|
||||
|
||||
export { type IAppState, type IDialogsOpen };
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
ICreateChannelRequest,
|
||||
IUpdateChannelRequest,
|
||||
IFetchChannelResponse,
|
||||
ICreateChannelResponse,
|
||||
IUpdateChannelResponse,
|
||||
|
|
@ -27,7 +28,7 @@ type ChannelAction =
|
|||
}
|
||||
| {
|
||||
type: ChannelActionTypes.SET_ACTIVE_CHANNEL;
|
||||
payload: string;
|
||||
payload: string | undefined;
|
||||
}
|
||||
| { type: ChannelActionTypes.FETCH_CHANNEL_START; payload: string }
|
||||
| {
|
||||
|
|
@ -42,7 +43,10 @@ type ChannelAction =
|
|||
type: ChannelActionTypes.CREATE_CHANNEL_FINISH;
|
||||
payload: ICreateChannelResponse;
|
||||
}
|
||||
| { type: ChannelActionTypes.UPDATE_CHANNEL_START; payload: string }
|
||||
| {
|
||||
type: ChannelActionTypes.UPDATE_CHANNEL_START;
|
||||
payload: IUpdateChannelRequest;
|
||||
}
|
||||
| {
|
||||
type: ChannelActionTypes.UPDATE_CHANNEL_FINISH;
|
||||
payload: IUpdateChannelResponse;
|
||||
|
|
|
|||
|
|
@ -26,27 +26,26 @@ function channelReducer(state: IChannelState, action: ChannelAction) {
|
|||
createChannel(action.payload.name, action.payload.communityId);
|
||||
break;
|
||||
case ChannelActionTypes.CREATE_CHANNEL_FINISH:
|
||||
setState("channel", "channels", {
|
||||
...state.channels,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("channel", "channels", action.payload.id, action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.UPDATE_CHANNEL_START:
|
||||
updateChannel(action.payload);
|
||||
updateChannel(
|
||||
action.payload.id,
|
||||
action.payload.name,
|
||||
action.payload.description,
|
||||
);
|
||||
break;
|
||||
case ChannelActionTypes.UPDATE_CHANNEL_FINISH:
|
||||
setState("channel", "channels", {
|
||||
...state.channels,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("channel", "channels", action.payload.id, action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.REMOVE_CHANNEL_START:
|
||||
removeChannel(action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.REMOVE_CHANNEL_FINISH:
|
||||
setState("channel", "channels", {
|
||||
...state.channels,
|
||||
[action.payload.id]: undefined,
|
||||
setState("channel", "channels", (channels) => {
|
||||
const copy = { ...channels };
|
||||
delete copy[action.payload.id];
|
||||
return copy;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
interface IChannelState {
|
||||
active: string;
|
||||
active?: string;
|
||||
channels: Record<string, IChannel>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import {
|
||||
ICreateCommunityRequest,
|
||||
IUpdateCommunityRequest,
|
||||
IFetchCommunityResponse,
|
||||
ICreateCommunityResponse,
|
||||
IUpdateCommunityResponse,
|
||||
IRemoveCommunityResponse,
|
||||
IFetchCommunityChannelsResponse,
|
||||
IFetchCommunityRolesResponse,
|
||||
IFetchCommunityMembersResponse,
|
||||
IFetchCommunityInvitesResponse,
|
||||
} from "../../api/community";
|
||||
import { IFetchUserCommunity } from "../../api/user";
|
||||
|
||||
|
|
@ -11,12 +17,20 @@ enum CommunityActionTypes {
|
|||
SET_ACTIVE_COMMUNITY = "SET_ACTIVE_COMMUNITY",
|
||||
FETCH_COMMUNITY_START = "FETCH_COMMUNITY_START",
|
||||
FETCH_COMMUNITY_FINISH = "FETCH_COMMUNITY_FINISH",
|
||||
CREATE_COMMUNITY_START = "CREATE_COMMUNITY_START",
|
||||
CREATE_COMMUNITY_FINISH = "CREATE_COMMUNITY_FINISH",
|
||||
UPDATE_COMMUNITY_START = "UPDATE_COMMUNITY_START",
|
||||
UPDATE_COMMUNITY_FINISH = "UPDATE_COMMUNITY_FINISH",
|
||||
REMOVE_COMMUNITY_START = "REMOVE_COMMUNITY_START",
|
||||
REMOVE_COMMUNITY_FINISH = "REMOVE_COMMUNITY_FINISH",
|
||||
FETCH_COMMUNITY_CHANNELS_START = "FETCH_COMMUNITY_CHANNELS_START",
|
||||
FETCH_COMMUNITY_CHANNELS_FINISH = "FETCH_COMMUNITY_CHANNELS_FINISH",
|
||||
FETCH_COMMUNITY_ROLES_START = "FETCH_COMMUNITY_ROLES_START",
|
||||
FETCH_COMMUNITY_ROLES_FINISH = "FETCH_COMMUNITY_ROLES_FINISH",
|
||||
FETCH_COMMUNITY_MEMBERS_START = "FETCH_COMMUNITY_MEMBERS_START",
|
||||
FETCH_COMMUNITY_MEMBERS_FINISH = "FETCH_COMMUNITY_MEMBERS_FINISH",
|
||||
FETCH_COMMUNITY_INVITES_START = "FETCH_COMMUNITY_INVITES_START",
|
||||
FETCH_COMMUNITY_INVITES_FINISH = "FETCH_COMMUNITY_INVITES_FINISH",
|
||||
}
|
||||
|
||||
type CommunityAction =
|
||||
|
|
@ -26,13 +40,34 @@ type CommunityAction =
|
|||
}
|
||||
| {
|
||||
type: CommunityActionTypes.SET_ACTIVE_COMMUNITY;
|
||||
payload: string;
|
||||
payload: string | undefined;
|
||||
}
|
||||
| { type: CommunityActionTypes.FETCH_COMMUNITY_START; payload: string }
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_FINISH;
|
||||
payload: IFetchCommunityResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.CREATE_COMMUNITY_START;
|
||||
payload: ICreateCommunityRequest;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.CREATE_COMMUNITY_FINISH;
|
||||
payload: ICreateCommunityResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.UPDATE_COMMUNITY_START;
|
||||
payload: IUpdateCommunityRequest;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.UPDATE_COMMUNITY_FINISH;
|
||||
payload: IUpdateCommunityResponse;
|
||||
}
|
||||
| { type: CommunityActionTypes.REMOVE_COMMUNITY_START; payload: string }
|
||||
| {
|
||||
type: CommunityActionTypes.REMOVE_COMMUNITY_FINISH;
|
||||
payload: IRemoveCommunityResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_START;
|
||||
payload: string;
|
||||
|
|
@ -56,6 +91,14 @@ type CommunityAction =
|
|||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_FINISH;
|
||||
payload: IFetchCommunityMembersResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_INVITES_START;
|
||||
payload: string;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_INVITES_FINISH;
|
||||
payload: IFetchCommunityInvitesResponse;
|
||||
};
|
||||
|
||||
export { CommunityActionTypes, type CommunityAction };
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import {
|
||||
fetchCommunity,
|
||||
createCommunity,
|
||||
updateCommunity,
|
||||
removeCommunity,
|
||||
fetchCommunityChannels,
|
||||
fetchCommunityRoles,
|
||||
fetchCommunityMembers,
|
||||
fetchCommunityInvites,
|
||||
} from "../../services/community";
|
||||
import { setState } from "../state";
|
||||
import { CommunityActionTypes, CommunityAction } from "./actions";
|
||||
|
|
@ -32,6 +36,42 @@ function communityReducer(state: ICommunityState, action: CommunityAction) {
|
|||
action.payload,
|
||||
);
|
||||
break;
|
||||
case CommunityActionTypes.CREATE_COMMUNITY_START:
|
||||
createCommunity(action.payload.name);
|
||||
break;
|
||||
case CommunityActionTypes.CREATE_COMMUNITY_FINISH:
|
||||
setState(
|
||||
"community",
|
||||
"communities",
|
||||
action.payload.id,
|
||||
action.payload,
|
||||
);
|
||||
break;
|
||||
case CommunityActionTypes.UPDATE_COMMUNITY_START:
|
||||
updateCommunity(
|
||||
action.payload.id,
|
||||
action.payload.name,
|
||||
action.payload.description,
|
||||
);
|
||||
break;
|
||||
case CommunityActionTypes.UPDATE_COMMUNITY_FINISH:
|
||||
setState(
|
||||
"community",
|
||||
"communities",
|
||||
action.payload.id,
|
||||
action.payload,
|
||||
);
|
||||
break;
|
||||
case CommunityActionTypes.REMOVE_COMMUNITY_START:
|
||||
removeCommunity(action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.REMOVE_COMMUNITY_FINISH:
|
||||
setState("community", "communities", (communities) => {
|
||||
const copy = { ...communities };
|
||||
delete copy[action.payload.id];
|
||||
return copy;
|
||||
});
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_START:
|
||||
fetchCommunityChannels(action.payload);
|
||||
break;
|
||||
|
|
@ -56,6 +96,14 @@ function communityReducer(state: ICommunityState, action: CommunityAction) {
|
|||
members: action.payload.members.map((member) => member.id),
|
||||
});
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_INVITES_START:
|
||||
fetchCommunityInvites(action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_INVITES_FINISH:
|
||||
setState("community", "communities", action.payload.id, {
|
||||
invites: action.payload.invites.map((invite) => invite.id),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
interface ICommunityState {
|
||||
active: string;
|
||||
active?: string;
|
||||
communities: Record<string, ICommunity>;
|
||||
}
|
||||
|
||||
|
|
@ -12,6 +12,7 @@ interface ICommunity {
|
|||
channels?: string[];
|
||||
roles?: string[];
|
||||
members?: string[];
|
||||
invites?: string[];
|
||||
}
|
||||
|
||||
export { type ICommunityState, type ICommunity };
|
||||
|
|
|
|||
39
src/store/invite/actions.ts
Normal file
39
src/store/invite/actions.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { IFetchCommunityInvite } from "../../api/community";
|
||||
import {
|
||||
IFetchInviteResponse,
|
||||
IRemoveInviteResponse,
|
||||
IAcceptInviteResponse,
|
||||
} from "../../api/invite";
|
||||
|
||||
enum InviteActionTypes {
|
||||
SET_INVITE = "SET_INVITE",
|
||||
FETCH_INVITE_START = "FETCH_INVITE_START",
|
||||
FETCH_INVITE_FINISH = "FETCH_INVITE_FINISH",
|
||||
REMOVE_INVITE_START = "REMOVE_INVITE_START",
|
||||
REMOVE_INVITE_FINISH = "REMOVE_INVITE_FINISH",
|
||||
ACCEPT_INVITE_START = "ACCEPT_INVITE_START",
|
||||
ACCEPT_INVITE_FINISH = "ACCEPT_INVITE_FINISH",
|
||||
}
|
||||
|
||||
type InviteAction =
|
||||
| {
|
||||
type: InviteActionTypes.SET_INVITE;
|
||||
payload: IFetchCommunityInvite;
|
||||
}
|
||||
| { type: InviteActionTypes.FETCH_INVITE_START; payload: string }
|
||||
| {
|
||||
type: InviteActionTypes.FETCH_INVITE_FINISH;
|
||||
payload: IFetchInviteResponse;
|
||||
}
|
||||
| { type: InviteActionTypes.REMOVE_INVITE_START; payload: string }
|
||||
| {
|
||||
type: InviteActionTypes.REMOVE_INVITE_FINISH;
|
||||
payload: IRemoveInviteResponse;
|
||||
}
|
||||
| { type: InviteActionTypes.ACCEPT_INVITE_START; payload: string }
|
||||
| {
|
||||
type: InviteActionTypes.ACCEPT_INVITE_FINISH;
|
||||
payload: IAcceptInviteResponse;
|
||||
};
|
||||
|
||||
export { InviteActionTypes, type InviteAction };
|
||||
3
src/store/invite/index.ts
Normal file
3
src/store/invite/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./invite";
|
||||
export * from "./actions";
|
||||
export * from "./types";
|
||||
35
src/store/invite/invite.ts
Normal file
35
src/store/invite/invite.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { fetchInvite, removeInvite, acceptInvite } from "../../services/invite";
|
||||
import { setState } from "../state";
|
||||
import { InviteActionTypes, InviteAction } from "./actions";
|
||||
import { IInviteState } from "./types";
|
||||
|
||||
function inviteReducer(state: IInviteState, action: InviteAction) {
|
||||
switch (action.type) {
|
||||
case InviteActionTypes.SET_INVITE:
|
||||
setState("invite", "invites", action.payload.id, action.payload);
|
||||
break;
|
||||
case InviteActionTypes.FETCH_INVITE_START:
|
||||
fetchInvite(action.payload);
|
||||
break;
|
||||
case InviteActionTypes.FETCH_INVITE_FINISH:
|
||||
setState("invite", "invites", action.payload.id, action.payload);
|
||||
break;
|
||||
case InviteActionTypes.REMOVE_INVITE_START:
|
||||
removeInvite(action.payload);
|
||||
break;
|
||||
case InviteActionTypes.REMOVE_INVITE_FINISH:
|
||||
setState("invite", "invites", (invites) => {
|
||||
const copy = { ...invites };
|
||||
delete copy[action.payload.id];
|
||||
return copy;
|
||||
});
|
||||
break;
|
||||
case InviteActionTypes.ACCEPT_INVITE_START:
|
||||
acceptInvite(action.payload);
|
||||
break;
|
||||
case InviteActionTypes.ACCEPT_INVITE_FINISH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export { inviteReducer };
|
||||
17
src/store/invite/types.ts
Normal file
17
src/store/invite/types.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
interface IInviteState {
|
||||
invites: Record<string, IInvite>;
|
||||
}
|
||||
|
||||
interface IInvite {
|
||||
id: string;
|
||||
communityId?: string;
|
||||
valid?: boolean;
|
||||
unlimitedInvites?: boolean;
|
||||
hasExpiration?: boolean;
|
||||
totalInvites?: number;
|
||||
remainingInvites?: number;
|
||||
creationDate?: number;
|
||||
expirationDate?: number;
|
||||
}
|
||||
|
||||
export { type IInviteState, type IInvite };
|
||||
|
|
@ -1,17 +1,23 @@
|
|||
import { IState } from "./types";
|
||||
import { Action } from "./actions";
|
||||
import { AppAction, appReducer } from "./app";
|
||||
import { AuthAction, authReducer } from "./auth";
|
||||
import { UserAction, userReducer } from "./user";
|
||||
import { CommunityAction, communityReducer } from "./community";
|
||||
import { ChannelAction, channelReducer } from "./channel";
|
||||
import { RoleAction, roleReducer } from "./role";
|
||||
import { SessionAction, sessionReducer } from "./session";
|
||||
import { InviteAction, inviteReducer } from "./invite";
|
||||
|
||||
function reducer(state: IState, action: Action) {
|
||||
appReducer(state.app, action as AppAction);
|
||||
authReducer(state.auth, action as AuthAction);
|
||||
userReducer(state.user, action as UserAction);
|
||||
communityReducer(state.community, action as CommunityAction);
|
||||
channelReducer(state.channel, action as ChannelAction);
|
||||
roleReducer(state.role, action as RoleAction);
|
||||
sessionReducer(state.session, action as SessionAction);
|
||||
inviteReducer(state.invite, action as InviteAction);
|
||||
}
|
||||
|
||||
export { reducer };
|
||||
|
|
|
|||
|
|
@ -23,27 +23,22 @@ function roleReducer(state: IRoleState, action: RoleAction) {
|
|||
createRole(action.payload.name, action.payload.communityId);
|
||||
break;
|
||||
case RoleActionTypes.CREATE_ROLE_FINISH:
|
||||
setState("role", "roles", {
|
||||
...state.roles,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("role", "roles", action.payload.id, action.payload);
|
||||
break;
|
||||
case RoleActionTypes.UPDATE_ROLE_START:
|
||||
updateRole(action.payload);
|
||||
break;
|
||||
case RoleActionTypes.UPDATE_ROLE_FINISH:
|
||||
setState("role", "roles", {
|
||||
...state.roles,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("role", "roles", action.payload.id, action.payload);
|
||||
break;
|
||||
case RoleActionTypes.REMOVE_ROLE_START:
|
||||
removeRole(action.payload);
|
||||
break;
|
||||
case RoleActionTypes.REMOVE_ROLE_FINISH:
|
||||
setState("role", "roles", {
|
||||
...state.roles,
|
||||
[action.payload.id]: undefined,
|
||||
setState("role", "roles", (roles) => {
|
||||
const copy = { ...roles };
|
||||
delete copy[action.payload.id];
|
||||
return copy;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
31
src/store/session/actions.ts
Normal file
31
src/store/session/actions.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { IFetchUserSession } from "../../api/user";
|
||||
import {
|
||||
IFetchSessionResponse,
|
||||
IRemoveSessionResponse,
|
||||
} from "../../api/session";
|
||||
|
||||
enum SessionActionTypes {
|
||||
SET_SESSION = "SET_SESSION",
|
||||
FETCH_SESSION_START = "FETCH_SESSION_START",
|
||||
FETCH_SESSION_FINISH = "FETCH_SESSION_FINISH",
|
||||
REMOVE_SESSION_START = "REMOVE_SESSION_START",
|
||||
REMOVE_SESSION_FINISH = "REMOVE_SESSION_FINISH",
|
||||
}
|
||||
|
||||
type SessionAction =
|
||||
| {
|
||||
type: SessionActionTypes.SET_SESSION;
|
||||
payload: IFetchUserSession;
|
||||
}
|
||||
| { type: SessionActionTypes.FETCH_SESSION_START; payload: string }
|
||||
| {
|
||||
type: SessionActionTypes.FETCH_SESSION_FINISH;
|
||||
payload: IFetchSessionResponse;
|
||||
}
|
||||
| { type: SessionActionTypes.REMOVE_SESSION_START; payload: string }
|
||||
| {
|
||||
type: SessionActionTypes.REMOVE_SESSION_FINISH;
|
||||
payload: IRemoveSessionResponse;
|
||||
};
|
||||
|
||||
export { SessionActionTypes, type SessionAction };
|
||||
3
src/store/session/index.ts
Normal file
3
src/store/session/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./session";
|
||||
export * from "./actions";
|
||||
export * from "./types";
|
||||
30
src/store/session/session.ts
Normal file
30
src/store/session/session.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { fetchSession, removeSession } from "../../services/session";
|
||||
import { setState } from "../state";
|
||||
import { SessionActionTypes, SessionAction } from "./actions";
|
||||
import { ISessionState } from "./types";
|
||||
|
||||
function sessionReducer(state: ISessionState, action: SessionAction) {
|
||||
switch (action.type) {
|
||||
case SessionActionTypes.SET_SESSION:
|
||||
setState("session", "sessions", action.payload.id, action.payload);
|
||||
break;
|
||||
case SessionActionTypes.FETCH_SESSION_START:
|
||||
fetchSession(action.payload);
|
||||
break;
|
||||
case SessionActionTypes.FETCH_SESSION_FINISH:
|
||||
setState("session", "sessions", action.payload.id, action.payload);
|
||||
break;
|
||||
case SessionActionTypes.REMOVE_SESSION_START:
|
||||
removeSession(action.payload);
|
||||
break;
|
||||
case SessionActionTypes.REMOVE_SESSION_FINISH:
|
||||
setState("session", "sessions", (sessions) => {
|
||||
const copy = { ...sessions };
|
||||
delete copy[action.payload.id];
|
||||
return copy;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export { sessionReducer };
|
||||
11
src/store/session/types.ts
Normal file
11
src/store/session/types.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
interface ISessionState {
|
||||
sessions: Record<string, ISession>;
|
||||
}
|
||||
|
||||
interface ISession {
|
||||
id: string;
|
||||
userId?: string;
|
||||
creationDate?: number;
|
||||
}
|
||||
|
||||
export { type ISessionState, type ISession };
|
||||
|
|
@ -4,6 +4,13 @@ import { Action } from "./actions";
|
|||
import { reducer } from "./reducers";
|
||||
|
||||
const [state, setState] = createStore<IState>({
|
||||
app: {
|
||||
homeOpen: true,
|
||||
dialogsOpen: {
|
||||
settingsOpen: false,
|
||||
addCommunityOpen: false,
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
session: undefined,
|
||||
},
|
||||
|
|
@ -20,6 +27,12 @@ const [state, setState] = createStore<IState>({
|
|||
role: {
|
||||
roles: {},
|
||||
},
|
||||
session: {
|
||||
sessions: {},
|
||||
},
|
||||
invite: {
|
||||
invites: {},
|
||||
},
|
||||
});
|
||||
|
||||
function dispatch(action: Action) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
import { IAppState } from "./app";
|
||||
import { IAuthState } from "./auth";
|
||||
import { IUserState } from "./user";
|
||||
import { ICommunityState } from "./community";
|
||||
import { IChannelState } from "./channel";
|
||||
import { IRoleState } from "./role";
|
||||
import { ISessionState } from "./session";
|
||||
import { IInviteState } from "./invite";
|
||||
|
||||
interface IState {
|
||||
app: IAppState;
|
||||
auth: IAuthState;
|
||||
user: IUserState;
|
||||
community: ICommunityState;
|
||||
channel: IChannelState;
|
||||
role: IRoleState;
|
||||
session: ISessionState;
|
||||
invite: IInviteState;
|
||||
}
|
||||
|
||||
export { type IState };
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { IFetchCommunityMember } from "../../api/community";
|
|||
import {
|
||||
IFetchLoggedUserResponse,
|
||||
IFetchUserResponse,
|
||||
IFetchUserSessionsResponse,
|
||||
IFetchUserCommunitiesResponse,
|
||||
} from "../../api/user";
|
||||
|
||||
|
|
@ -11,6 +12,8 @@ enum UserActionTypes {
|
|||
FETCH_LOGGED_USER_ID_FINISH = "FETCH_LOGGED_USER_ID_FINISH",
|
||||
FETCH_USER_START = "FETCH_USER_START",
|
||||
FETCH_USER_FINISH = "FETCH_USER_FINISH",
|
||||
FETCH_USER_SESSIONS_START = "FETCH_USER_SESSIONS_START",
|
||||
FETCH_USER_SESSIONS_FINISH = "FETCH_USER_SESSIONS_FINISH",
|
||||
FETCH_USER_COMMUNITIES_START = "FETCH_USER_COMMUNITIES_START",
|
||||
FETCH_USER_COMMUNITIES_FINISH = "FETCH_USER_COMMUNITIES_FINISH",
|
||||
}
|
||||
|
|
@ -27,6 +30,11 @@ type UserAction =
|
|||
}
|
||||
| { type: UserActionTypes.FETCH_USER_START; payload: string }
|
||||
| { type: UserActionTypes.FETCH_USER_FINISH; payload: IFetchUserResponse }
|
||||
| { type: UserActionTypes.FETCH_USER_SESSIONS_START; payload: string }
|
||||
| {
|
||||
type: UserActionTypes.FETCH_USER_SESSIONS_FINISH;
|
||||
payload: IFetchUserSessionsResponse;
|
||||
}
|
||||
| { type: UserActionTypes.FETCH_USER_COMMUNITIES_START; payload: string }
|
||||
| {
|
||||
type: UserActionTypes.FETCH_USER_COMMUNITIES_FINISH;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ interface IUser {
|
|||
admin?: boolean;
|
||||
registerDate?: number;
|
||||
lastLogin?: number;
|
||||
sessions?: string[];
|
||||
communities?: string[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
fetchLoggedUser,
|
||||
fetchUser,
|
||||
fetchUserSessions,
|
||||
fetchUserCommunities,
|
||||
} from "../../services/user";
|
||||
import { setState } from "../state";
|
||||
|
|
@ -24,6 +25,14 @@ function userReducer(state: IUserState, action: UserAction) {
|
|||
case UserActionTypes.FETCH_USER_FINISH:
|
||||
setState("user", "users", action.payload.id, action.payload);
|
||||
break;
|
||||
case UserActionTypes.FETCH_USER_SESSIONS_START:
|
||||
fetchUserSessions(action.payload);
|
||||
break;
|
||||
case UserActionTypes.FETCH_USER_SESSIONS_FINISH:
|
||||
setState("user", "users", action.payload.id, {
|
||||
sessions: action.payload.sessions.map((session) => session.id),
|
||||
});
|
||||
break;
|
||||
case UserActionTypes.FETCH_USER_COMMUNITIES_START:
|
||||
fetchUserCommunities(action.payload);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { createEffect, createMemo, type Component } from "solid-js";
|
||||
import { CommunityView } from "../CommunityView";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { CommunityActionTypes, ICommunity } from "../../store/community";
|
||||
import { ChannelActionTypes } from "../../store/channel";
|
||||
|
|
@ -23,7 +22,7 @@ const ChannelView: Component = () => {
|
|||
|
||||
const communityInfo = createMemo<ICommunity | undefined>(() => {
|
||||
const activeCommunityId = state.community.active;
|
||||
return state.community.communities[activeCommunityId];
|
||||
return state.community.communities[activeCommunityId ?? 0];
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
|
|
@ -63,9 +62,7 @@ const ChannelView: Component = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div class="flex flex-row bg-stone-900 w-80 shadow-panel z-20">
|
||||
<CommunityView />
|
||||
<div class="h-full w-full relative">
|
||||
<div class="bg-stone-900 w-80 shadow-panel z-20 h-full relative">
|
||||
<CommunityBar
|
||||
id={communityInfo()?.id}
|
||||
name={communityInfo()?.name}
|
||||
|
|
@ -78,7 +75,6 @@ const ChannelView: Component = () => {
|
|||
{channelIds().map(mapChannel)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ const ChatView: Component = () => {
|
|||
|
||||
const channelInfo = createMemo<IChannel | undefined>(() => {
|
||||
const activeChannelId = state.channel.active;
|
||||
return state.channel.channels[activeChannelId];
|
||||
return state.channel.channels[activeChannelId ?? 0];
|
||||
});
|
||||
|
||||
let scrollRef: HTMLUListElement | undefined;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import { createMemo, type Component } from "solid-js";
|
|||
import { Community } from "../../components/Community";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { CommunityActionTypes } from "../../store/community";
|
||||
import { SidebarItem } from "../../components/SidebarItem";
|
||||
import { AppActionTypes } from "../../store/app";
|
||||
import { HomeIcon, PlusIcon, SettingsIcon } from "../../components/icons";
|
||||
|
||||
const CommunityView: Component = () => {
|
||||
const communityIds = createMemo(() => {
|
||||
|
|
@ -18,7 +21,25 @@ const CommunityView: Component = () => {
|
|||
return loggedUser.communities ?? [];
|
||||
});
|
||||
|
||||
const onHomeClick = () => {
|
||||
dispatch({
|
||||
type: CommunityActionTypes.SET_ACTIVE_COMMUNITY,
|
||||
payload: undefined,
|
||||
});
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_HOME_OPEN,
|
||||
payload: true,
|
||||
});
|
||||
};
|
||||
|
||||
const onCommunityClick = (id: string) => {
|
||||
if (state.app.homeOpen) {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_HOME_OPEN,
|
||||
payload: false,
|
||||
});
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_START,
|
||||
payload: id,
|
||||
|
|
@ -29,6 +50,20 @@ const CommunityView: Component = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const onNewClick = () => {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_ADD_COMMUNITY_OPEN,
|
||||
payload: true,
|
||||
});
|
||||
};
|
||||
|
||||
const onSettingsClick = () => {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_SETTINGS_OPEN,
|
||||
payload: true,
|
||||
});
|
||||
};
|
||||
|
||||
const mapCommunity = (communityId: string) => {
|
||||
const community = state.community.communities[communityId];
|
||||
if (!community) {
|
||||
|
|
@ -49,8 +84,22 @@ const CommunityView: Component = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div class="bg-stone-950 w-18 h-full shadow-panel z-30 flex flex-col p-2 gap-2">
|
||||
<div class="flex flex-col bg-stone-950 w-16 h-full shadow-panel z-30 p-2 gap-2">
|
||||
<SidebarItem
|
||||
icon={HomeIcon}
|
||||
active={state.app.homeOpen}
|
||||
onClick={onHomeClick}
|
||||
/>
|
||||
<div class="divider my-0"></div>
|
||||
{communityIds().map(mapCommunity)}
|
||||
<div class="divider my-0"></div>
|
||||
<SidebarItem icon={PlusIcon} active={false} onClick={onNewClick} />
|
||||
<div class="flex-1"></div>
|
||||
<SidebarItem
|
||||
icon={SettingsIcon}
|
||||
active={false}
|
||||
onClick={onSettingsClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
42
src/views/HomeView/HomeView.tsx
Normal file
42
src/views/HomeView/HomeView.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { type Component } from "solid-js";
|
||||
import { PlusIcon, SettingsIcon } from "../../components/icons";
|
||||
import { HomeCard } from "../../components/HomeCard";
|
||||
import { dispatch } from "../../store/state";
|
||||
import { AppActionTypes } from "../../store/app";
|
||||
|
||||
const HomeView: Component = () => {
|
||||
const onNewClick = () => {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_ADD_COMMUNITY_OPEN,
|
||||
payload: true,
|
||||
});
|
||||
};
|
||||
|
||||
const onSettingsClick = () => {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_SETTINGS_OPEN,
|
||||
payload: true,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="flex-1 flex flex-row bg-stone-900 shadow-panel z-0">
|
||||
<div class="flex-1 flex flex-row items-center justify-center gap-8">
|
||||
<HomeCard
|
||||
title="Find a Community"
|
||||
description="Find or create a new Community to chat"
|
||||
icon={PlusIcon}
|
||||
onClick={onNewClick}
|
||||
/>
|
||||
<HomeCard
|
||||
title="Open Settings"
|
||||
description="Adjust your settings"
|
||||
icon={SettingsIcon}
|
||||
onClick={onSettingsClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { HomeView };
|
||||
1
src/views/HomeView/index.ts
Normal file
1
src/views/HomeView/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./HomeView";
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
import { createEffect, createMemo, onMount, type Component } from "solid-js";
|
||||
import { createEffect, onMount, type Component } from "solid-js";
|
||||
import { ChannelView } from "../ChannelView";
|
||||
import { ChatView } from "../ChatView";
|
||||
import { MemberView } from "../MemberView";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { UserActionTypes } from "../../store/user";
|
||||
import { AuthActionTypes } from "../../store/auth";
|
||||
import { HomeView } from "../HomeView";
|
||||
import { CommunityView } from "../CommunityView";
|
||||
import { ModalView } from "../ModalView";
|
||||
|
||||
const MainView: Component = () => {
|
||||
onMount(() => {
|
||||
|
|
@ -30,9 +33,19 @@ const MainView: Component = () => {
|
|||
|
||||
return (
|
||||
<div class="flex flex-row h-screen">
|
||||
<ModalView />
|
||||
<CommunityView />
|
||||
{state.app.homeOpen ? (
|
||||
<>
|
||||
<HomeView />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ChannelView />
|
||||
<ChatView />
|
||||
<MemberView />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
55
src/views/ModalView/ModalView.tsx
Normal file
55
src/views/ModalView/ModalView.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { createEffect, type Component } from "solid-js";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import SettingsModal from "../../components/SettingsModal/SettingsModal";
|
||||
import CommunityModal from "../../components/CommunityModal/CommunityModal";
|
||||
import { AppActionTypes } from "../../store/app";
|
||||
|
||||
const ModalView: Component = () => {
|
||||
let settingsModal: HTMLDialogElement;
|
||||
let communityModal: HTMLDialogElement;
|
||||
|
||||
createEffect(() => {
|
||||
if (state.app.dialogsOpen.settingsOpen) {
|
||||
settingsModal.showModal();
|
||||
} else {
|
||||
settingsModal.close();
|
||||
}
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
if (state.app.dialogsOpen.addCommunityOpen) {
|
||||
communityModal.showModal();
|
||||
} else {
|
||||
communityModal.close();
|
||||
}
|
||||
});
|
||||
|
||||
const onCloseSettings = () => {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_SETTINGS_OPEN,
|
||||
payload: false,
|
||||
});
|
||||
};
|
||||
|
||||
const onCloseCommunity = () => {
|
||||
dispatch({
|
||||
type: AppActionTypes.SET_ADD_COMMUNITY_OPEN,
|
||||
payload: false,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsModal
|
||||
dialogRef={(element) => (settingsModal = element)}
|
||||
onClose={onCloseSettings}
|
||||
/>
|
||||
<CommunityModal
|
||||
dialogRef={(element) => (communityModal = element)}
|
||||
onClose={onCloseCommunity}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export { ModalView };
|
||||
1
src/views/ModalView/index.ts
Normal file
1
src/views/ModalView/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./ModalView";
|
||||
Loading…
Add table
Add a link
Reference in a new issue