Communities and channels
This commit is contained in:
parent
79dbeb6b7a
commit
280158470a
34 changed files with 558 additions and 62 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "pulsar-web",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
import { callApi, HTTP } from "../tools";
|
||||
import { IFetchCommunityRequest, IFetchCommunityResponse } from "./types";
|
||||
import {
|
||||
IFetchCommunityRequest,
|
||||
IFetchCommunityResponse,
|
||||
IFetchCommunityChannelsRequest,
|
||||
IFetchCommunityChannelsResponse,
|
||||
IFetchCommunityRolesRequest,
|
||||
IFetchCommunityRolesResponse,
|
||||
IFetchCommunityMembersRequest,
|
||||
IFetchCommunityMembersResponse,
|
||||
} from "./types";
|
||||
|
||||
const fetchCommunityApi = async (
|
||||
request: IFetchCommunityRequest,
|
||||
|
|
@ -7,4 +16,27 @@ const fetchCommunityApi = async (
|
|||
return await callApi(HTTP.GET, `community/${request.id}`);
|
||||
};
|
||||
|
||||
export { fetchCommunityApi };
|
||||
const fetchCommunityChannelsApi = async (
|
||||
request: IFetchCommunityChannelsRequest,
|
||||
): Promise<IFetchCommunityChannelsResponse> => {
|
||||
return await callApi(HTTP.GET, `community/${request.id}/channels`);
|
||||
};
|
||||
|
||||
const fetchCommunityRolesApi = async (
|
||||
request: IFetchCommunityRolesRequest,
|
||||
): Promise<IFetchCommunityRolesResponse> => {
|
||||
return await callApi(HTTP.GET, `community/${request.id}/roles`);
|
||||
};
|
||||
|
||||
const fetchCommunityMembersApi = async (
|
||||
request: IFetchCommunityMembersRequest,
|
||||
): Promise<IFetchCommunityMembersResponse> => {
|
||||
return await callApi(HTTP.GET, `community/${request.id}/members`);
|
||||
};
|
||||
|
||||
export {
|
||||
fetchCommunityApi,
|
||||
fetchCommunityChannelsApi,
|
||||
fetchCommunityRolesApi,
|
||||
fetchCommunityMembersApi,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,8 +12,59 @@ interface IFetchCommunityRequest {
|
|||
|
||||
interface IFetchCommunityResponse extends IFetchCommunity {}
|
||||
|
||||
interface IFetchCommunityChannelsRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityChannelsResponse {
|
||||
id: string;
|
||||
channels: IFetchCommunityChannel[];
|
||||
}
|
||||
|
||||
interface IFetchCommunityChannel {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityRolesRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityRolesResponse {
|
||||
id: string;
|
||||
roles: IFetchCommunityRole[];
|
||||
}
|
||||
|
||||
interface IFetchCommunityRole {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityMembersRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IFetchCommunityMembersResponse {
|
||||
id: string;
|
||||
members: IFetchCommunityMember[];
|
||||
}
|
||||
|
||||
interface IFetchCommunityMember {
|
||||
id: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export {
|
||||
type IFetchCommunity,
|
||||
type IFetchCommunityRequest,
|
||||
type IFetchCommunityResponse,
|
||||
type IFetchCommunityChannelsRequest,
|
||||
type IFetchCommunityChannelsResponse,
|
||||
type IFetchCommunityChannel,
|
||||
type IFetchCommunityRolesRequest,
|
||||
type IFetchCommunityRolesResponse,
|
||||
type IFetchCommunityRole,
|
||||
type IFetchCommunityMembersRequest,
|
||||
type IFetchCommunityMembersResponse,
|
||||
type IFetchCommunityMember,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { IChannelProps } from "./types";
|
||||
|
||||
const Channel: Component = () => {
|
||||
return <div></div>;
|
||||
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)}
|
||||
>
|
||||
<div class="font-bold text-xl"> #</div>
|
||||
<div class="font-bold">{props.name}</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export { Channel };
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export * from "./Channel";
|
||||
export * from "./types";
|
||||
|
|
|
|||
8
src/components/Channel/types.ts
Normal file
8
src/components/Channel/types.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
interface IChannelProps {
|
||||
id: string;
|
||||
name: string;
|
||||
active: boolean;
|
||||
onChannelClick: (id: string) => void;
|
||||
}
|
||||
|
||||
export { type IChannelProps };
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { IChannelBarProps } from "./types";
|
||||
|
||||
const ChannelBar: Component = () => {
|
||||
const ChannelBar: Component<IChannelBarProps> = (props: IChannelBarProps) => {
|
||||
return (
|
||||
<div class="absolute w-full top-0 z-10">
|
||||
<div class="bg-stone-800/25 backdrop-blur-md h-16 w-full shadow-bar p-2"></div>
|
||||
<div class="flex flex-col justify-center bg-stone-800/25 backdrop-blur-md h-16 w-full shadow-bar px-5">
|
||||
<h2 class="text-sm font-bold">
|
||||
{props.name ? `# ${props.name}` : undefined}
|
||||
</h2>
|
||||
<p class="text-xs">{props.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export * from "./ChannelBar";
|
||||
export * from "./types";
|
||||
|
|
|
|||
7
src/components/ChannelBar/types.ts
Normal file
7
src/components/ChannelBar/types.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
interface IChannelBarProps {
|
||||
id?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export { type IChannelBarProps };
|
||||
|
|
@ -7,7 +7,9 @@ const Community: Component<ICommunityProps> = (props: ICommunityProps) => {
|
|||
class="avatar cursor-pointer"
|
||||
onClick={() => props.onCommunityClick(props.id)}
|
||||
>
|
||||
<div class="w-full rounded-full">
|
||||
<div
|
||||
class={`w-full transition-[border-radius] duration-300 outline-stone-300 hover:outline-2 ${props.active ? "rounded-lg outline-2" : "rounded-4xl"}`}
|
||||
>
|
||||
<img src={props.avatar} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ interface ICommunityProps {
|
|||
id: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
active: boolean;
|
||||
onCommunityClick: (id: string) => void;
|
||||
}
|
||||
|
||||
|
|
|
|||
19
src/components/CommunityBar/CommunityBar.tsx
Normal file
19
src/components/CommunityBar/CommunityBar.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { ICommunityBarProps } from "./types";
|
||||
|
||||
const CommunityBar: Component<ICommunityBarProps> = (
|
||||
props: ICommunityBarProps,
|
||||
) => {
|
||||
return (
|
||||
<div
|
||||
class={`absolute w-full top-0 z-10 bg-cover bg-top bg-no-repeat bg-[url('${props.avatar}')]`}
|
||||
>
|
||||
<div class="flex flex-col justify-center bg-stone-800/25 backdrop-blur-md h-16 w-full shadow-bar px-5">
|
||||
<h2 class="text-sm font-bold">{props.name}</h2>
|
||||
<p class="text-xs">{props.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { CommunityBar };
|
||||
2
src/components/CommunityBar/index.ts
Normal file
2
src/components/CommunityBar/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./CommunityBar";
|
||||
export * from "./types";
|
||||
8
src/components/CommunityBar/types.ts
Normal file
8
src/components/CommunityBar/types.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
interface ICommunityBarProps {
|
||||
id?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
avatar?: string;
|
||||
}
|
||||
|
||||
export { type ICommunityBarProps };
|
||||
|
|
@ -1,7 +1,20 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { IMemberProps } from "./types";
|
||||
|
||||
const Member: Component = () => {
|
||||
return <div></div>;
|
||||
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)}
|
||||
>
|
||||
<div class="avatar">
|
||||
<div class="w-9 rounded-full">
|
||||
<img src={props.avatar} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="font-bold">{props.username}</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export { Member };
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export * from "./Member";
|
||||
export * from "./types";
|
||||
|
|
|
|||
9
src/components/Member/types.ts
Normal file
9
src/components/Member/types.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
interface IMemberProps {
|
||||
id: string;
|
||||
username: string;
|
||||
avatar: string;
|
||||
active: boolean;
|
||||
onMemberClick: (id: string) => void;
|
||||
}
|
||||
|
||||
export { type IMemberProps };
|
||||
|
|
@ -3,7 +3,7 @@ import { IMessageProps } from "./types";
|
|||
|
||||
const Message: Component<IMessageProps> = (props: IMessageProps) => {
|
||||
return (
|
||||
<li class="list-row hover:bg-stone-700">
|
||||
<li class="list-row p-3 hover:bg-stone-700">
|
||||
<div
|
||||
class="avatar cursor-pointer"
|
||||
onClick={() => props.onProfileClick(props.userId)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { state } from "../../store/state";
|
||||
|
||||
const MessageBar: Component = () => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
import { fetchCommunityApi } from "../../api/community";
|
||||
import {
|
||||
fetchCommunityApi,
|
||||
fetchCommunityChannelsApi,
|
||||
fetchCommunityRolesApi,
|
||||
fetchCommunityMembersApi,
|
||||
} 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";
|
||||
|
||||
const fetchCommunity = async (id: string) => {
|
||||
|
|
@ -13,4 +21,63 @@ const fetchCommunity = async (id: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
export { fetchCommunity };
|
||||
const fetchCommunityChannels = async (id: string) => {
|
||||
const data = await fetchCommunityChannelsApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
data.channels.forEach((channel) => {
|
||||
dispatch({
|
||||
type: ChannelActionTypes.SET_CHANNEL,
|
||||
payload: channel,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const fetchCommunityRoles = async (id: string) => {
|
||||
const data = await fetchCommunityRolesApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_ROLES_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
data.roles.forEach((role) => {
|
||||
dispatch({
|
||||
type: RoleActionTypes.SET_ROLE,
|
||||
payload: role,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const fetchCommunityMembers = async (id: string) => {
|
||||
const data = await fetchCommunityMembersApi({
|
||||
id: id,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_FINISH,
|
||||
payload: data,
|
||||
});
|
||||
|
||||
data.members.forEach((member) => {
|
||||
dispatch({
|
||||
type: UserActionTypes.SET_USER,
|
||||
payload: member,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
fetchCommunity,
|
||||
fetchCommunityChannels,
|
||||
fetchCommunityRoles,
|
||||
fetchCommunityMembers,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ import {
|
|||
IUpdateChannelResponse,
|
||||
IRemoveChannelResponse,
|
||||
} from "../../api/channel";
|
||||
import { IFetchCommunityChannel } from "../../api/community";
|
||||
|
||||
enum ChannelActionTypes {
|
||||
FETCH_CHANNEL_START = "FETCH_COMMUNITY_START",
|
||||
FETCH_CHANNEL_FINISH = "FETCH_COMMUNITY_FINISH",
|
||||
SET_CHANNEL = "SET_CHANNEL",
|
||||
SET_ACTIVE_CHANNEL = "SET_ACTIVE_CHANNEL",
|
||||
FETCH_CHANNEL_START = "FETCH_CHANNEL_START",
|
||||
FETCH_CHANNEL_FINISH = "FETCH_CHANNEL_FINISH",
|
||||
CREATE_CHANNEL_START = "CREATE_CHANNEL_START",
|
||||
CREATE_CHANNEL_FINISH = "CREATE_CHANNEL_FINISH",
|
||||
UPDATE_CHANNEL_START = "UPDATE_CHANNEL_START",
|
||||
|
|
@ -18,6 +21,14 @@ enum ChannelActionTypes {
|
|||
}
|
||||
|
||||
type ChannelAction =
|
||||
| {
|
||||
type: ChannelActionTypes.SET_CHANNEL;
|
||||
payload: IFetchCommunityChannel;
|
||||
}
|
||||
| {
|
||||
type: ChannelActionTypes.SET_ACTIVE_CHANNEL;
|
||||
payload: string;
|
||||
}
|
||||
| { type: ChannelActionTypes.FETCH_CHANNEL_START; payload: string }
|
||||
| {
|
||||
type: ChannelActionTypes.FETCH_CHANNEL_FINISH;
|
||||
|
|
|
|||
|
|
@ -10,14 +10,17 @@ import { IChannelState } from "./types";
|
|||
|
||||
function channelReducer(state: IChannelState, action: ChannelAction) {
|
||||
switch (action.type) {
|
||||
case ChannelActionTypes.SET_CHANNEL:
|
||||
setState("channel", "channels", action.payload.id, action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.SET_ACTIVE_CHANNEL:
|
||||
setState("channel", "active", action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.FETCH_CHANNEL_START:
|
||||
fetchChannel(action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.FETCH_CHANNEL_FINISH:
|
||||
setState("channel", "channels", {
|
||||
...state.channels,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("channel", "channels", action.payload.id, action.payload);
|
||||
break;
|
||||
case ChannelActionTypes.CREATE_CHANNEL_START:
|
||||
createChannel(action.payload.name, action.payload.communityId);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
interface IChannelState {
|
||||
active: string;
|
||||
channels: Record<string, IChannel>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,61 @@
|
|||
import { IFetchCommunityResponse } from "../../api/community";
|
||||
import {
|
||||
IFetchCommunityResponse,
|
||||
IFetchCommunityChannelsResponse,
|
||||
IFetchCommunityRolesResponse,
|
||||
IFetchCommunityMembersResponse,
|
||||
} from "../../api/community";
|
||||
import { IFetchUserCommunity } from "../../api/user";
|
||||
|
||||
enum CommunityActionTypes {
|
||||
SET_COMMUNITY = "SET_COMMUNITY",
|
||||
SET_ACTIVE_COMMUNITY = "SET_ACTIVE_COMMUNITY",
|
||||
FETCH_COMMUNITY_START = "FETCH_COMMUNITY_START",
|
||||
FETCH_COMMUNITY_FINISH = "FETCH_COMMUNITY_FINISH",
|
||||
SET_COMMUNITY = "SET_COMMUNITY",
|
||||
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",
|
||||
}
|
||||
|
||||
type CommunityAction =
|
||||
| {
|
||||
type: CommunityActionTypes.SET_COMMUNITY;
|
||||
payload: IFetchUserCommunity;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.SET_ACTIVE_COMMUNITY;
|
||||
payload: string;
|
||||
}
|
||||
| { type: CommunityActionTypes.FETCH_COMMUNITY_START; payload: string }
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_FINISH;
|
||||
payload: IFetchCommunityResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.SET_COMMUNITY;
|
||||
payload: IFetchUserCommunity;
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_START;
|
||||
payload: string;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_FINISH;
|
||||
payload: IFetchCommunityChannelsResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_ROLES_START;
|
||||
payload: string;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_ROLES_FINISH;
|
||||
payload: IFetchCommunityRolesResponse;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_START;
|
||||
payload: string;
|
||||
}
|
||||
| {
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_FINISH;
|
||||
payload: IFetchCommunityMembersResponse;
|
||||
};
|
||||
|
||||
export { CommunityActionTypes, type CommunityAction };
|
||||
|
|
|
|||
|
|
@ -1,23 +1,59 @@
|
|||
import { fetchCommunity } from "../../services/community";
|
||||
import {
|
||||
fetchCommunity,
|
||||
fetchCommunityChannels,
|
||||
fetchCommunityRoles,
|
||||
fetchCommunityMembers,
|
||||
} from "../../services/community";
|
||||
import { setState } from "../state";
|
||||
import { CommunityActionTypes, CommunityAction } from "./actions";
|
||||
import { ICommunityState } from "./types";
|
||||
|
||||
function communityReducer(state: ICommunityState, action: CommunityAction) {
|
||||
switch (action.type) {
|
||||
case CommunityActionTypes.SET_COMMUNITY:
|
||||
setState(
|
||||
"community",
|
||||
"communities",
|
||||
action.payload.id,
|
||||
action.payload,
|
||||
);
|
||||
break;
|
||||
case CommunityActionTypes.SET_ACTIVE_COMMUNITY:
|
||||
setState("community", "active", action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_START:
|
||||
fetchCommunity(action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_FINISH:
|
||||
setState("community", "communities", {
|
||||
...state.communities,
|
||||
[action.payload.id]: action.payload,
|
||||
setState(
|
||||
"community",
|
||||
"communities",
|
||||
action.payload.id,
|
||||
action.payload,
|
||||
);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_START:
|
||||
fetchCommunityChannels(action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_FINISH:
|
||||
setState("community", "communities", action.payload.id, {
|
||||
channels: action.payload.channels.map((channel) => channel.id),
|
||||
});
|
||||
break;
|
||||
case CommunityActionTypes.SET_COMMUNITY:
|
||||
setState("community", "communities", {
|
||||
...state.communities,
|
||||
[action.payload.id]: action.payload,
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_ROLES_START:
|
||||
fetchCommunityRoles(action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_ROLES_FINISH:
|
||||
setState("community", "communities", action.payload.id, {
|
||||
roles: action.payload.roles.map((role) => role.id),
|
||||
});
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_START:
|
||||
fetchCommunityMembers(action.payload);
|
||||
break;
|
||||
case CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_FINISH:
|
||||
setState("community", "communities", action.payload.id, {
|
||||
members: action.payload.members.map((member) => member.id),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
interface ICommunityState {
|
||||
active: string;
|
||||
communities: Record<string, ICommunity>;
|
||||
}
|
||||
|
||||
|
|
@ -8,6 +9,9 @@ interface ICommunity {
|
|||
description?: string;
|
||||
owner?: string;
|
||||
creationDate?: number;
|
||||
channels?: string[];
|
||||
roles?: string[];
|
||||
members?: string[];
|
||||
}
|
||||
|
||||
export { type ICommunityState, type ICommunity };
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { IFetchCommunityRole } from "../../api/community";
|
||||
import {
|
||||
ICreateRoleRequest,
|
||||
IFetchRoleResponse,
|
||||
|
|
@ -7,6 +8,7 @@ import {
|
|||
} from "../../api/role";
|
||||
|
||||
enum RoleActionTypes {
|
||||
SET_ROLE = "SET_ROLE",
|
||||
FETCH_ROLE_START = "FETCH_ROLE_START",
|
||||
FETCH_ROLE_FINISH = "FETCH_ROLE_FINISH",
|
||||
CREATE_ROLE_START = "CREATE_ROLE_START",
|
||||
|
|
@ -18,6 +20,10 @@ enum RoleActionTypes {
|
|||
}
|
||||
|
||||
type RoleAction =
|
||||
| {
|
||||
type: RoleActionTypes.SET_ROLE;
|
||||
payload: IFetchCommunityRole;
|
||||
}
|
||||
| { type: RoleActionTypes.FETCH_ROLE_START; payload: string }
|
||||
| {
|
||||
type: RoleActionTypes.FETCH_ROLE_FINISH;
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ import { IRoleState } from "./types";
|
|||
|
||||
function roleReducer(state: IRoleState, action: RoleAction) {
|
||||
switch (action.type) {
|
||||
case RoleActionTypes.SET_ROLE:
|
||||
setState("role", "roles", action.payload.id, action.payload);
|
||||
break;
|
||||
case RoleActionTypes.FETCH_ROLE_START:
|
||||
fetchRole(action.payload);
|
||||
break;
|
||||
case RoleActionTypes.FETCH_ROLE_FINISH:
|
||||
setState("role", "roles", {
|
||||
...state.roles,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("role", "roles", action.payload.id, action.payload);
|
||||
break;
|
||||
case RoleActionTypes.CREATE_ROLE_START:
|
||||
createRole(action.payload.name, action.payload.communityId);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { IFetchCommunityMember } from "../../api/community";
|
||||
import {
|
||||
IFetchLoggedUserResponse,
|
||||
IFetchUserResponse,
|
||||
|
|
@ -5,6 +6,7 @@ import {
|
|||
} from "../../api/user";
|
||||
|
||||
enum UserActionTypes {
|
||||
SET_USER = "SET_USER",
|
||||
FETCH_LOGGED_USER_ID_START = "FETCH_LOGGED_USER_ID_START",
|
||||
FETCH_LOGGED_USER_ID_FINISH = "FETCH_LOGGED_USER_ID_FINISH",
|
||||
FETCH_USER_START = "FETCH_USER_START",
|
||||
|
|
@ -14,6 +16,10 @@ enum UserActionTypes {
|
|||
}
|
||||
|
||||
type UserAction =
|
||||
| {
|
||||
type: UserActionTypes.SET_USER;
|
||||
payload: IFetchCommunityMember;
|
||||
}
|
||||
| { type: UserActionTypes.FETCH_LOGGED_USER_ID_START }
|
||||
| {
|
||||
type: UserActionTypes.FETCH_LOGGED_USER_ID_FINISH;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import { IUserState } from "./types";
|
|||
|
||||
function userReducer(state: IUserState, action: UserAction) {
|
||||
switch (action.type) {
|
||||
case UserActionTypes.SET_USER:
|
||||
setState("user", "users", action.payload.id, action.payload);
|
||||
break;
|
||||
case UserActionTypes.FETCH_LOGGED_USER_ID_START:
|
||||
fetchLoggedUser();
|
||||
break;
|
||||
|
|
@ -19,23 +22,16 @@ function userReducer(state: IUserState, action: UserAction) {
|
|||
fetchUser(action.payload);
|
||||
break;
|
||||
case UserActionTypes.FETCH_USER_FINISH:
|
||||
setState("user", "users", {
|
||||
...state.users,
|
||||
[action.payload.id]: action.payload,
|
||||
});
|
||||
setState("user", "users", action.payload.id, action.payload);
|
||||
break;
|
||||
case UserActionTypes.FETCH_USER_COMMUNITIES_START:
|
||||
fetchUserCommunities(action.payload);
|
||||
break;
|
||||
case UserActionTypes.FETCH_USER_COMMUNITIES_FINISH:
|
||||
setState("user", "users", {
|
||||
...state.users,
|
||||
[action.payload.id]: {
|
||||
id: action.payload.id,
|
||||
communities: action.payload.communities.map(
|
||||
(community) => community.id,
|
||||
),
|
||||
},
|
||||
setState("user", "users", action.payload.id, {
|
||||
communities: action.payload.communities.map(
|
||||
(community) => community.id,
|
||||
),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,83 @@
|
|||
import type { Component } from "solid-js";
|
||||
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";
|
||||
import { Channel } from "../../components/Channel";
|
||||
import { CommunityBar } from "../../components/CommunityBar";
|
||||
|
||||
const ChannelView: Component = () => {
|
||||
const channelIds = createMemo(() => {
|
||||
const activeCommunityId = state.community.active;
|
||||
if (!activeCommunityId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const community = state.community.communities[activeCommunityId];
|
||||
if (!community) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return community.channels ?? [];
|
||||
});
|
||||
|
||||
const communityInfo = createMemo<ICommunity | undefined>(() => {
|
||||
const activeCommunityId = state.community.active;
|
||||
return state.community.communities[activeCommunityId];
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
if (state.community.active) {
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_CHANNELS_START,
|
||||
payload: state.community.active,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const onChannelClick = (id: string) => {
|
||||
dispatch({
|
||||
type: ChannelActionTypes.FETCH_CHANNEL_START,
|
||||
payload: id,
|
||||
});
|
||||
dispatch({
|
||||
type: ChannelActionTypes.SET_ACTIVE_CHANNEL,
|
||||
payload: id,
|
||||
});
|
||||
};
|
||||
|
||||
const mapChannel = (channelId: string) => {
|
||||
const channel = state.channel.channels[channelId];
|
||||
if (!channel) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<Channel
|
||||
id={channel.id}
|
||||
name={channel.name ?? ""}
|
||||
active={channel.id === state.channel.active}
|
||||
onChannelClick={onChannelClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="bg-stone-900 w-96 shadow-panel z-20">
|
||||
<div class="flex flex-row bg-stone-900 w-80 shadow-panel z-20">
|
||||
<CommunityView />
|
||||
<div></div>
|
||||
<div class="h-full w-full relative">
|
||||
<CommunityBar
|
||||
id={communityInfo()?.id}
|
||||
name={communityInfo()?.name}
|
||||
description={communityInfo()?.description}
|
||||
avatar={
|
||||
"https://img.daisyui.com/images/profile/demo/yellingcat@192.webp"
|
||||
}
|
||||
/>
|
||||
<ul class="h-full list flex flex-col p-2 gap-1 pt-18 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-500 scrollbar-track-gray-800">
|
||||
{channelIds().map(mapChannel)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { onMount, type Component } from "solid-js";
|
||||
import { createMemo, onMount, type Component } from "solid-js";
|
||||
import { ChannelBar } from "../../components/ChannelBar";
|
||||
import { MessageBar } from "../../components/MessageBar";
|
||||
import { Message } from "../../components/Message";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { UserActionTypes } from "../../store/user";
|
||||
import { IChannel } from "../../store/channel";
|
||||
|
||||
const ChatView: Component = () => {
|
||||
const testMessages = [
|
||||
|
|
@ -175,6 +178,11 @@ const ChatView: Component = () => {
|
|||
},
|
||||
];
|
||||
|
||||
const channelInfo = createMemo<IChannel | undefined>(() => {
|
||||
const activeChannelId = state.channel.active;
|
||||
return state.channel.channels[activeChannelId];
|
||||
});
|
||||
|
||||
let scrollRef: HTMLUListElement | undefined;
|
||||
onMount(() => {
|
||||
if (scrollRef) {
|
||||
|
|
@ -183,16 +191,23 @@ const ChatView: Component = () => {
|
|||
});
|
||||
|
||||
const onProfileClick = (userId: string) => {
|
||||
console.log(userId);
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_START,
|
||||
payload: userId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="bg-stone-800 flex-1 z-0 relative">
|
||||
<div class="h-full">
|
||||
<ChannelBar />
|
||||
<ChannelBar
|
||||
id={channelInfo()?.id}
|
||||
name={channelInfo()?.name}
|
||||
description={channelInfo()?.description}
|
||||
/>
|
||||
<ul
|
||||
ref={scrollRef}
|
||||
class="h-full list flex flex-col p-2 pt-16 pb-24 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-500 scrollbar-track-gray-800"
|
||||
class="h-full list flex flex-col p-2 pt-18 pb-24 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-500 scrollbar-track-gray-800"
|
||||
>
|
||||
{testMessages.map((msg) => (
|
||||
<Message
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { createMemo, type Component } from "solid-js";
|
||||
import { Community } from "../../components/Community";
|
||||
import { state } from "../../store/state";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { CommunityActionTypes } from "../../store/community";
|
||||
|
||||
const CommunityView: Component = () => {
|
||||
const communityIds = createMemo(() => {
|
||||
|
|
@ -18,7 +19,14 @@ const CommunityView: Component = () => {
|
|||
});
|
||||
|
||||
const onCommunityClick = (id: string) => {
|
||||
console.log(id);
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_START,
|
||||
payload: id,
|
||||
});
|
||||
dispatch({
|
||||
type: CommunityActionTypes.SET_ACTIVE_COMMUNITY,
|
||||
payload: id,
|
||||
});
|
||||
};
|
||||
|
||||
const mapCommunity = (communityId: string) => {
|
||||
|
|
@ -34,16 +42,15 @@ const CommunityView: Component = () => {
|
|||
avatar={
|
||||
"https://img.daisyui.com/images/profile/demo/yellingcat@192.webp"
|
||||
}
|
||||
active={community.id === state.community.active}
|
||||
onCommunityClick={onCommunityClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="p-3 h-full">
|
||||
<div class="bg-stone-950 w-20 h-full rounded-full shadow-panel z-30 flex flex-col p-3 gap-3">
|
||||
{communityIds().map(mapCommunity)}
|
||||
</div>
|
||||
<div class="bg-stone-950 w-18 h-full shadow-panel z-30 flex flex-col p-2 gap-2">
|
||||
{communityIds().map(mapCommunity)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,68 @@
|
|||
import type { Component } from "solid-js";
|
||||
import { createEffect, createMemo, type Component } from "solid-js";
|
||||
import { dispatch, state } from "../../store/state";
|
||||
import { CommunityActionTypes } from "../../store/community";
|
||||
import { UserActionTypes } from "../../store/user";
|
||||
import { Member } from "../../components/Member";
|
||||
|
||||
const MemberView: Component = () => {
|
||||
return <div class="bg-stone-900 w-64 shadow-panel z-20"></div>;
|
||||
const memberIds = createMemo(() => {
|
||||
const activeCommunityId = state.community.active;
|
||||
if (!activeCommunityId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const community = state.community.communities[activeCommunityId];
|
||||
if (!community) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return community.members ?? [];
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
if (state.community.active) {
|
||||
dispatch({
|
||||
type: CommunityActionTypes.FETCH_COMMUNITY_MEMBERS_START,
|
||||
payload: state.community.active,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const onMemberClick = (id: string) => {
|
||||
dispatch({
|
||||
type: UserActionTypes.FETCH_USER_START,
|
||||
payload: id,
|
||||
});
|
||||
};
|
||||
|
||||
const mapMember = (memberId: string) => {
|
||||
const member = state.user.users[memberId];
|
||||
if (!member) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<Member
|
||||
id={member.id}
|
||||
username={member.username ?? ""}
|
||||
avatar={
|
||||
"https://img.daisyui.com/images/profile/demo/yellingcat@192.webp"
|
||||
}
|
||||
active={false}
|
||||
onMemberClick={onMemberClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="bg-stone-900 w-64 shadow-panel z-20 relative">
|
||||
<div class="h-full">
|
||||
<ul class="h-full list flex flex-col p-2 gap-1 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-500 scrollbar-track-gray-800">
|
||||
{memberIds().map(mapMember)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { MemberView };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue