upd
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
options: string[];
|
||||
customOption?: React.ReactNode;
|
||||
}
|
||||
|
||||
function CustomSelect({ options, customOption }: Props) {
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||
|
||||
// Сбрасываем selectedOption при изменении options
|
||||
useEffect(() => {
|
||||
setSelectedOption(null);
|
||||
}, [options]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{options.map((option, index) => (
|
||||
<div key={index} onClick={() => setSelectedOption(option)}>
|
||||
{customOption ? customOption(option) : option}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomSelect;
|
||||
@@ -4,25 +4,28 @@ import MoreIcon from "./icons/MoreIcon";
|
||||
import api from "../utils/api";
|
||||
import PlusIcon from "./icons/PlusIcon";
|
||||
import { IServer } from "../types/IServer";
|
||||
import useModalStore from "../stores/useModalStore";
|
||||
import CreateSessionModal from "./modals/CreateSessionModal";
|
||||
|
||||
interface IDesktopCardProps {
|
||||
server: IServer;
|
||||
}
|
||||
|
||||
export default function DesktopCard({ server }: IDesktopCardProps) {
|
||||
const { setModal, setPosition } = useModalStore();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { mutate: createSession } = useMutation({
|
||||
mutationFn: () =>
|
||||
api.post(`sessions`, {
|
||||
json: {
|
||||
serverId: server.id,
|
||||
clientId: "abcfd570-2fa8-4f55-957b-5007f84f8f96",
|
||||
appId: "b8a9995c-a799-4593-8f96-03942050cb21",
|
||||
},
|
||||
}),
|
||||
onMutate: () => queryClient.invalidateQueries({ queryKey: ["sessions"] }),
|
||||
});
|
||||
// const { mutate: createSession } = useMutation({
|
||||
// mutationFn: () =>
|
||||
// api.post(`sessions`, {
|
||||
// json: {
|
||||
// serverId: server.id,
|
||||
// clientId: "abcfd570-2fa8-4f55-957b-5007f84f8f96",
|
||||
// appId: "b8a9995c-a799-4593-8f96-03942050cb21",
|
||||
// },
|
||||
// }),
|
||||
// onMutate: () => queryClient.invalidateQueries({ queryKey: ["sessions"] }),
|
||||
// });
|
||||
|
||||
const { mutate: endSession } = useMutation({
|
||||
mutationKey: ["sessions", server.sessions?.[0]?.id],
|
||||
@@ -33,6 +36,11 @@ export default function DesktopCard({ server }: IDesktopCardProps) {
|
||||
onMutate: () => queryClient.invalidateQueries({ queryKey: ["sessions"] }),
|
||||
});
|
||||
|
||||
async function handleClickCreateSession() {
|
||||
setPosition("right");
|
||||
setModal(<CreateSessionModal servers={[server]} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-[1.111vw] rounded-[0.833vw] flex flex-col justify-between gap-[1.111vw] aspect-[272/149] w-[25.208vw] border border-[#00000014]">
|
||||
<div className="flex justify-between items-start">
|
||||
@@ -102,7 +110,7 @@ export default function DesktopCard({ server }: IDesktopCardProps) {
|
||||
<Button
|
||||
variant="primary"
|
||||
className="bg-[#798FFF] w-full rounded-[0.556vw]"
|
||||
onClick={() => createSession()}
|
||||
onClick={handleClickCreateSession}
|
||||
>
|
||||
<div className="flex gap-1 items-center">
|
||||
<span className="w-[1.389vw] h-[1.389vw]">
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { useState } from 'react';
|
||||
import { IServer } from '../types/IServer';
|
||||
import Button from './Button';
|
||||
import { useClickAway } from '@uidotdev/usehooks';
|
||||
import ArrowDownIcon from './icons/ArrowDownIcon';
|
||||
import { useState } from "react";
|
||||
import { IServer } from "../types/IServer";
|
||||
import Button from "./Button";
|
||||
import { useClickAway } from "@uidotdev/usehooks";
|
||||
import ArrowDownIcon from "./icons/ArrowDownIcon";
|
||||
|
||||
interface Props {
|
||||
servers: IServer[];
|
||||
value: IServer;
|
||||
value: IServer | undefined;
|
||||
onChange: (server: IServer) => void;
|
||||
}
|
||||
|
||||
export default function DesktopSelect({ servers, value, onChange }: Props) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const ref = useClickAway<HTMLDivElement>(() => setIsOpen(false));
|
||||
|
||||
return (
|
||||
@@ -27,22 +26,26 @@ export default function DesktopSelect({ servers, value, onChange }: Props) {
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
<div className="flex gap-[0.278vw] items-center">
|
||||
<div
|
||||
className="rounded-full w-[0.417vw] aspect-square"
|
||||
style={{
|
||||
backgroundColor:
|
||||
value.sessions &&
|
||||
value.sessions?.length > 0 &&
|
||||
value.sessions[value.sessions.length - 1].status === 'started'
|
||||
? '#EF3C26'
|
||||
: '#108C33',
|
||||
}}
|
||||
/>
|
||||
<p className="text-[0.972vw] leading-[115%]">{value.name}</p>
|
||||
{value?.name && (
|
||||
<div
|
||||
className="rounded-full w-[0.417vw] aspect-square"
|
||||
style={{
|
||||
backgroundColor:
|
||||
value?.sessions &&
|
||||
value.sessions?.length > 0 &&
|
||||
value.sessions[value.sessions.length - 1].status === "started"
|
||||
? "#EF3C26"
|
||||
: "#108C33",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<p className="text-[0.972vw] leading-[115%]">
|
||||
{value?.name || "Выберите из списка"}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`w-[1.389vw] transition-transform h-[1.389vw]${
|
||||
isOpen ? ' rotate-180' : ''
|
||||
isOpen ? " rotate-180" : ""
|
||||
}`}
|
||||
>
|
||||
<ArrowDownIcon />
|
||||
@@ -69,9 +72,9 @@ export default function DesktopSelect({ servers, value, onChange }: Props) {
|
||||
server.sessions &&
|
||||
server.sessions?.length > 0 &&
|
||||
server.sessions[server.sessions.length - 1].status ===
|
||||
'started'
|
||||
? '#EF3C26'
|
||||
: '#108C33',
|
||||
"started"
|
||||
? "#EF3C26"
|
||||
: "#108C33",
|
||||
}}
|
||||
/>
|
||||
<p className="text-[0.972vw] leading-[115%]">{server.name}</p>
|
||||
|
||||
+30
-15
@@ -1,19 +1,35 @@
|
||||
import { useState } from 'react';
|
||||
import Button from './Button';
|
||||
import { useClickAway } from '@uidotdev/usehooks';
|
||||
import ArrowDownIcon from './icons/ArrowDownIcon';
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from "react";
|
||||
import Button from "./Button";
|
||||
import { useClickAway } from "@uidotdev/usehooks";
|
||||
import ArrowDownIcon from "./icons/ArrowDownIcon";
|
||||
|
||||
interface Props {
|
||||
options: string[];
|
||||
value: string;
|
||||
onChange: (option: string) => void;
|
||||
options: string[]; // ["StroyProject"]
|
||||
onChange: (option: string | undefined) => void;
|
||||
}
|
||||
|
||||
export default function Select({ options, value, onChange }: Props) {
|
||||
export default function Select({ options, onChange }: Props) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const [selectedOption, setSelectedOption] = useState<string | undefined>();
|
||||
const ref = useClickAway<HTMLDivElement>(() => setIsOpen(false));
|
||||
|
||||
function handleClickOption(option: string) {
|
||||
setSelectedOption(option);
|
||||
onChange(option);
|
||||
setIsOpen(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(selectedOption);
|
||||
}, [selectedOption]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedOption && !options.includes(selectedOption)) {
|
||||
setSelectedOption(undefined);
|
||||
}
|
||||
}, [options]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
@@ -25,10 +41,12 @@ export default function Select({ options, value, onChange }: Props) {
|
||||
className="px-[0.833vw] py-[0.417vw] !justify-between w-full"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
<p className="text-[0.972vw] leading-[115%]">{value}</p>
|
||||
<p className="text-[0.972vw] leading-[115%]">
|
||||
{selectedOption || "Выберите из списка"}
|
||||
</p>
|
||||
<div
|
||||
className={`w-[1.389vw] transition-transform h-[1.389vw]${
|
||||
isOpen ? ' rotate-180' : ''
|
||||
isOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
>
|
||||
<ArrowDownIcon />
|
||||
@@ -42,10 +60,7 @@ export default function Select({ options, value, onChange }: Props) {
|
||||
onlyIcon
|
||||
variant="tertiary"
|
||||
className="px-[0.833vw] py-[0.417vw] !justify-start w-full !first:rounded-t-[0.556vw] !last:rounded-b-[0.556vw]"
|
||||
onClick={() => {
|
||||
onChange(option);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
onClick={() => handleClickOption(option)}
|
||||
>
|
||||
<div className="flex gap-[0.278vw] items-center">
|
||||
<p className="text-[0.972vw] leading-[115%]">{option}</p>
|
||||
|
||||
@@ -1,43 +1,74 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { IServer } from '../../types/IServer.ts';
|
||||
import Button from '../Button.tsx';
|
||||
import DesktopSelect from '../DesktopSelect.tsx';
|
||||
import Input from '../Input.tsx';
|
||||
import DisplayIcon from '../icons/DisplayIcon.tsx';
|
||||
import Select from '../Select.tsx';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { IUser } from '../../types/IUser.ts';
|
||||
import { IApp } from '../../types/IApp.ts';
|
||||
import { IServer } from "../../types/IServer.ts";
|
||||
import Button from "../Button.tsx";
|
||||
import DesktopSelect from "../DesktopSelect.tsx";
|
||||
import Input from "../Input.tsx";
|
||||
import DisplayIcon from "../icons/DisplayIcon.tsx";
|
||||
import Select from "../Select.tsx";
|
||||
import { useState } from "react";
|
||||
import { IApp } from "../../types/IApp.ts";
|
||||
import api from "../../utils/api.ts";
|
||||
import { ISession } from "../../types/ISession.ts";
|
||||
import { IClient } from "../../types/IClient.ts";
|
||||
import useModalStore from "../../stores/useModalStore.ts";
|
||||
|
||||
interface Props {
|
||||
servers: IServer[];
|
||||
}
|
||||
|
||||
export default function CreateSessionModal({ servers }: Props) {
|
||||
const queryClient = useQueryClient();
|
||||
const { setModal } = useModalStore();
|
||||
const [name, setName] = useState("");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [selectedServer, setSelectedServer] = useState<IServer>();
|
||||
const [selectedApp, setSelectedApp] = useState<IApp>();
|
||||
|
||||
const user = queryClient.getQueryData<IUser>(['me']);
|
||||
async function createClient() {
|
||||
console.log(name, phone, email);
|
||||
|
||||
const [selectedServer, setSelectedServer] = useState<IServer | undefined>(
|
||||
servers.find(
|
||||
({ sessions }) =>
|
||||
!sessions || !sessions.length || sessions[0].status === 'ended'
|
||||
)
|
||||
);
|
||||
return await api
|
||||
.post("clients", {
|
||||
json: {
|
||||
name,
|
||||
phone,
|
||||
email,
|
||||
},
|
||||
})
|
||||
.json<IClient>();
|
||||
}
|
||||
|
||||
const [selectedApp, setSelectedApp] = useState<IApp | undefined>(
|
||||
user?.company.apps.filter((app) => app.serverId === selectedServer?.id)[0]
|
||||
);
|
||||
async function createSession(clientId: string) {
|
||||
return await api
|
||||
.post("sessions", {
|
||||
json: {
|
||||
clientId,
|
||||
serverId: selectedServer?.id,
|
||||
appId: selectedApp?.id,
|
||||
},
|
||||
})
|
||||
.json<ISession>();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedApp(
|
||||
user?.company.apps.filter((app) => app.serverId === selectedServer?.id)[0]
|
||||
);
|
||||
}, [selectedServer, user?.company.apps]);
|
||||
async function handleClickCreateSession(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!name || !phone || !selectedServer || !selectedApp) return;
|
||||
|
||||
try {
|
||||
const client = await createClient();
|
||||
await createSession(client.id);
|
||||
|
||||
setModal(null);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-[34.375vw] rounded-[0.833vw] bg-white p-[1.667vw] flex flex-col min-h-[calc(100dvh-0.972vw*2)] justify-between gap-[1.111vw]">
|
||||
<form
|
||||
className="w-[34.375vw] rounded-[0.833vw] bg-white p-[1.667vw] flex flex-col min-h-[calc(100dvh-0.972vw*2)] justify-between gap-[1.111vw]"
|
||||
onSubmit={handleClickCreateSession}
|
||||
>
|
||||
<div className="gap-y-[1.111vw] flex flex-col justify-between">
|
||||
<div className="space-y-[0.556vw]">
|
||||
<div className="p-[0.833vw] ring-[0.069vw] ring-[#E6E6E6] w-fit rounded-[0.556vw]">
|
||||
@@ -56,7 +87,12 @@ export default function CreateSessionModal({ servers }: Props) {
|
||||
Имя <span className="text-[#C6C6C699]">*</span>
|
||||
</p>
|
||||
<div className="outline outline-black/10 rounded-[0.556vw] w-[13.889vw]">
|
||||
<Input placeholder="Константин" required />
|
||||
<Input
|
||||
placeholder="Константин"
|
||||
required
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
@@ -64,60 +100,76 @@ export default function CreateSessionModal({ servers }: Props) {
|
||||
Номер <span className="text-[#C6C6C699]">*</span>
|
||||
</p>
|
||||
<div className="outline outline-black/10 rounded-[0.556vw] w-[13.889vw]">
|
||||
<Input placeholder="+ 7 (999) 99 99 99" required type="tel" />
|
||||
<Input
|
||||
placeholder="79221234567"
|
||||
required
|
||||
type="tel"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[0.972vw]">Электронная почта</p>
|
||||
<div className="outline outline-black/10 rounded-[0.556vw] w-[13.889vw]">
|
||||
<Input placeholder="sample@mail.ru" type="email" />
|
||||
<Input
|
||||
placeholder="sample@mail.ru"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-[0.556vw]">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[0.972vw]">Стол</p>
|
||||
{selectedServer && (
|
||||
<DesktopSelect
|
||||
servers={servers}
|
||||
value={selectedServer}
|
||||
onChange={setSelectedServer}
|
||||
/>
|
||||
)}
|
||||
<DesktopSelect
|
||||
servers={servers.filter(
|
||||
({ sessions }) =>
|
||||
!sessions ||
|
||||
!sessions.length ||
|
||||
sessions[0]?.status === "ended"
|
||||
)}
|
||||
value={selectedServer || undefined}
|
||||
onChange={setSelectedServer}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[0.694vw] text-black/30 w-[13.889vw] leading-[115%] self-end">
|
||||
При запуске нового сеанса текущий будет завершен принудительно.
|
||||
</p>
|
||||
</div>
|
||||
{user && selectedServer && (
|
||||
{selectedServer && (
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[0.972vw]">Проекты</p>
|
||||
<div className="outline outline-black/10 rounded-[0.556vw] w-[13.889vw]">
|
||||
{selectedApp && (
|
||||
<Select
|
||||
options={user.company.apps
|
||||
.filter((app) => app.serverId === selectedServer.id)
|
||||
.map((app) => app.name)}
|
||||
value={selectedApp?.name}
|
||||
onChange={(option) =>
|
||||
setSelectedApp(
|
||||
user.company.apps.find((app) => app.name === option)
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Select
|
||||
options={selectedServer.apps?.map((app) => app.name) || []}
|
||||
onChange={(option) =>
|
||||
setSelectedApp(
|
||||
selectedServer.apps?.find((app) => app.name === option)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<hr className="border-black/10" />
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<Button className="bg-[#F9F9F9] px-[2.222vw] py-[0.556vw] !rounded-[0.556vw]">
|
||||
<Button
|
||||
type="button"
|
||||
className="bg-[#F9F9F9] px-[2.222vw] py-[0.556vw] !rounded-[0.556vw]"
|
||||
onClick={() => setModal(null)}
|
||||
>
|
||||
<p className="text-black font-medium text-[0.972vw]">Отменить</p>
|
||||
</Button>
|
||||
<Button className="bg-[#EF3C26] px-[2.222vw] py-[0.556vw] !rounded-[0.556vw]">
|
||||
<Button
|
||||
type="submit"
|
||||
className="bg-[#EF3C26] px-[2.222vw] py-[0.556vw] !rounded-[0.556vw]"
|
||||
>
|
||||
<p className="text-[0.972vw] font-medium">Запустить сеанс</p>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,11 @@ import api from "../utils/api";
|
||||
import Sidebar from "../components/Sidebar";
|
||||
import { IServer } from "../types/IServer";
|
||||
import DesktopCard from "../components/DesktopCard";
|
||||
import Button from "../components/Button";
|
||||
import useModalStore from "../stores/useModalStore";
|
||||
import CreateSessionModal from "../components/modals/CreateSessionModal";
|
||||
|
||||
function DashboardPage() {
|
||||
const { data: me } = useQuery({
|
||||
queryKey: ["me"],
|
||||
queryFn: () => api.get("users/me").json<IUser>(),
|
||||
queryFn: () => api.get("auth/me").json<IUser>(),
|
||||
});
|
||||
|
||||
const { data: servers } = useQuery({
|
||||
@@ -21,13 +18,6 @@ function DashboardPage() {
|
||||
refetchInterval: 1000,
|
||||
});
|
||||
|
||||
const { setModal, setPosition } = useModalStore();
|
||||
|
||||
function handleClickCreateSession() {
|
||||
setPosition("right");
|
||||
setModal(<CreateSessionModal servers={servers || []} />);
|
||||
}
|
||||
|
||||
// async function logout() {
|
||||
// return await api.get("auth/logout").json();
|
||||
// }
|
||||
@@ -42,7 +32,7 @@ function DashboardPage() {
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className="p-[0.833vw] flex gap-[0.833vw] h-dvh">
|
||||
<div className="p-[0.833vw] flex gap-[0.833vw] min-h-dvh">
|
||||
<div className="w-[3.333vw] flex flex-col justify-between"></div>
|
||||
<div className="bg-white w-full rounded-[1.667vw] border border-black/5 p-[1.667vw] flex justify-between">
|
||||
<div className="w-[13.889vw] space-y-[1.667vw]">
|
||||
@@ -62,9 +52,7 @@ function DashboardPage() {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-green-200 w-[13.889vw]">
|
||||
<Button onClick={handleClickCreateSession}>открыть</Button>
|
||||
</div>
|
||||
<div className="bg-green-200 w-[13.889vw]">...</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+11
-8
@@ -10,7 +10,7 @@ import { useNavigate } from "react-router";
|
||||
|
||||
function LoginPage() {
|
||||
const navigate = useNavigate();
|
||||
const { token, setToken } = useAuthStore();
|
||||
const { setToken } = useAuthStore();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
@@ -28,16 +28,20 @@ function LoginPage() {
|
||||
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
|
||||
let result;
|
||||
|
||||
try {
|
||||
const { token } = await login();
|
||||
setToken(token);
|
||||
|
||||
toast.success("Вы успешно вошли в систему");
|
||||
|
||||
navigate("/");
|
||||
result = await login();
|
||||
} catch (error) {
|
||||
toast.error((await (error as HTTPError).response.json<IError>()).error);
|
||||
}
|
||||
|
||||
if (!result?.token) {
|
||||
return;
|
||||
}
|
||||
|
||||
setToken(result.token);
|
||||
navigate("/");
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -45,7 +49,6 @@ function LoginPage() {
|
||||
<div className="flex-1 flex flex-col gap-4 justify-between w-[380px]">
|
||||
<div className="flex flex-col items-center justify-between gap-4">
|
||||
<img src="/logo-mate.svg" alt="logo" />
|
||||
<p>{token}</p>
|
||||
</div>
|
||||
<div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
|
||||
@@ -9,7 +9,7 @@ function ProtectedPage() {
|
||||
|
||||
const { data: user, isLoading } = useQuery({
|
||||
queryKey: ['me'],
|
||||
queryFn: () => api.get('users/me').json<IUser>(),
|
||||
queryFn: () => api.get('auth/me').json<IUser>(),
|
||||
enabled: !!token,
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { IUser } from "./IUser";
|
||||
export interface ICompany {
|
||||
id: string;
|
||||
name: string;
|
||||
apps: IApp[];
|
||||
servers: IServer[];
|
||||
users: IUser[];
|
||||
apps?: IApp[];
|
||||
servers?: IServer[];
|
||||
users?: IUser[];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ISession } from './ISession';
|
||||
import { IApp } from "./IApp";
|
||||
import { ISession } from "./ISession";
|
||||
|
||||
export interface IServer {
|
||||
id: string;
|
||||
@@ -7,4 +8,5 @@ export interface IServer {
|
||||
location: string;
|
||||
companyId: string;
|
||||
sessions?: ISession[];
|
||||
apps?: IApp[];
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@ export interface IUser {
|
||||
email: string;
|
||||
fullname: string;
|
||||
companyId: string;
|
||||
company: ICompany
|
||||
company?: ICompany;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user