Add an initial organisation flow

This commit is contained in:
Ana Custura 2026-06-11 09:53:30 +01:00
parent 3bd1a5007a
commit ac733af3b5
12 changed files with 432 additions and 99 deletions

View file

@ -22,12 +22,14 @@
"@types/node": "^24.12.3", "@types/node": "^24.12.3",
"@types/react": "^19.2.14", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/react-highlight-words": "^0.20.1",
"@vitejs/plugin-react": "^6.0.1", "@vitejs/plugin-react": "^6.0.1",
"eslint": "^10.3.0", "eslint": "^10.3.0",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2", "eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0", "globals": "^17.6.0",
"react-highlight-words": "^0.21.0",
"typescript": "~6.0.2", "typescript": "~6.0.2",
"typescript-eslint": "^8.59.2", "typescript-eslint": "^8.59.2",
"vite": "^8.0.12" "vite": "^8.0.12"

View file

@ -5,19 +5,20 @@ import React, {useState} from 'react';
import { import {
SettingOutlined, SettingOutlined,
UserOutlined, UserOutlined,
DeploymentUnitOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import {Breadcrumb, type MenuProps} from 'antd'; import {Breadcrumb, type MenuProps} from 'antd';
import { Layout, Menu, theme } from 'antd'; import { Layout, Menu, theme } from 'antd';
import Home from "./Home.tsx"; import Home from "./Home.tsx";
import {Route, Routes, useLocation, useNavigate} from "react-router"; import {Route, Routes, useLocation, useNavigate} from "react-router";
import Profile from "./Profile.tsx"; import Profile from "./Profile.tsx";
import {type UserContextType} from './UserContext.tsx'; import {type UserContextType} from './hooks/UserContext.ts';
import {UserContext} from './UserContext.tsx'; import {UserContext} from './hooks/UserContext.ts';
import type {userObject} from "./UserContext.tsx"; import type {userObject} from "./hooks/UserContext.ts";
import {type OrgContextType} from './OrgContext.tsx'; import Organisations from "./Organisations.tsx";
import {OrgContext} from './OrgContext.tsx'; import {RefreshContext} from "./hooks/RefreshContext.ts";
import type {orgObject} from "./OrgContext.tsx"; import Bridges from "./Bridges.tsx";
const { Header, Content, Sider } = Layout; const { Header, Content, Sider } = Layout;
@ -66,28 +67,16 @@ const App: React.FC = () => {
first_name: "", first_name: "",
last_name: "", last_name: "",
email: "", email: "",
organisations: [] organisations: [],
id: -1
}, },
setCurrentUser: () => {} setCurrentUser: () => {}
} }
const defaultOrg: OrgContextType = {
currentOrg: {
billing_contact: "",
owner_contact: "",
name: "",
status: "",
root_user: "",
security_contact: "",
},
setCurrentOrg: () => {}
}
const [currentUser, setCurrentUser] = useState<userObject>(defaultUser.currentUser); const [currentUser, setCurrentUser] = useState<userObject>(defaultUser.currentUser);
const [currentOrg, setCurrentOrg] = useState<orgObject>(defaultOrg.currentOrg); const [refreshKey, setRefreshKey] = useState<number>(1);
// STRILL NEEDS SOMETHING TO get CURRENT USER ORGS and map first one to a CURRENT ORG fetched from the API
// STILL NEEDS THE WRAPPER IN THE RETURN STATEMETNS
/***************************** /*****************************
GETTING CURRENT USER FROM API GETTING CURRENT USER FROM API
*****************************/ *****************************/
@ -108,7 +97,7 @@ const App: React.FC = () => {
console.error(e); console.error(e);
} }
})(); })();
}, [auth]); }, [auth, refreshKey]);
if (!currentUser) { if (!currentUser) {
@ -142,8 +131,14 @@ const App: React.FC = () => {
case 'profile': case 'profile':
navigate('/profile'); navigate('/profile');
break; break;
case 'orgs':
navigate('/organisations');
break;
case 'logout': case 'logout':
auth.removeUser().then(r => navigate('/profile')); auth.removeUser().then(() => navigate('/profile'));
break;
case 'bridges':
navigate('/bridges');
break; break;
default: default:
console.log('Clicked item:', e.key); console.log('Clicked item:', e.key);
@ -151,19 +146,26 @@ const App: React.FC = () => {
}; };
//const organisations: [] = current_user.organisations; let side_nav_items: MenuItem[] = []
const side_nav_items: MenuItem[] = currentUser.organisations && [
getItem('Files', '9', <SettingOutlined />),
];
const top_nav_items = [ const top_nav_items = [
getItem(currentUser.first_name + " " +currentUser.last_name , 'account', <UserOutlined />, [getItem('Account details', 'profile'), getItem('Log out', 'logout')]), getItem(currentUser.first_name + " " +currentUser.last_name , 'account', <UserOutlined />, [getItem('Account details', 'profile'), getItem('Log out', 'logout')]),
getItem("Organisation Settings", 'orgsettings', <SettingOutlined />),
]; ];
if (currentUser.organisations.length > 0) {
side_nav_items = [ getItem('My organisations', 'orgs', <SettingOutlined />),
getItem('Bridges', 'bridges', <DeploymentUnitOutlined />), ];
const currentOrg = currentUser.organisations[0]['name']
top_nav_items.push(getItem(currentOrg +" Settings", 'orgsettings', <SettingOutlined />));
}
return ( return (
<UserContext.Provider value={{ currentUser, setCurrentUser }}> <UserContext.Provider value={{ currentUser, setCurrentUser }}>
<Layout> <RefreshContext.Provider value={{ refreshKey, setRefreshKey }}>
<Layout>
<Header style={{ display: 'flex', alignItems: 'right' }}> <Header style={{ display: 'flex', alignItems: 'right' }}>
<div className="demo-logo" > <div className="demo-logo" >
<h1>SR22</h1> <h1>SR22</h1>
@ -206,12 +208,15 @@ const App: React.FC = () => {
<Routes> <Routes>
<Route path="/" element={<Home/>}/> <Route path="/" element={<Home/>}/>
{currentUser && <Route path="/profile" element={<Profile/>}/> } {currentUser && <Route path="/profile" element={<Profile/>}/> }
{currentUser && <Route path="/organisations" element={<Organisations/>}/> }
{currentUser && <Route path="/bridges" element={<Bridges/>}/> }
</Routes> </Routes>
</Content> </Content>
</Layout> </Layout>
</Layout> </Layout>
</Layout> </Layout>
</RefreshContext.Provider>
</UserContext.Provider> </UserContext.Provider>
); );

163
src/Bridges.tsx Normal file
View file

@ -0,0 +1,163 @@
import { useRef, useState } from 'react';
import { SearchOutlined } from '@ant-design/icons';
import type { InputRef, TableColumnsType, TableColumnType } from 'antd';
import { Button, Input, Space, Table } from 'antd';
import type { FilterDropdownProps } from 'antd/es/table/interface';
import Highlighter from 'react-highlight-words';
import { QRCode, theme } from 'antd';
const { useToken } = theme;
interface BridgeDataType {
fingerprint: string;
bridgeline: string;
qrCodeText: string;
}
const Bridges = () => {
const bridgeLines: BridgeDataType[] = [
{fingerprint: '0C6DDE3F9FC377A5E69DC044E81C857277148D71', bridgeline: "obfs4 62.224.107.157:443 0C6DDE3F9FC377A5E69DC044E81C857277148D71 cert=6vp+cyZmJOp+QFtytv9Ca+Z+ASF4l7r12MeEevvufl4OcDimBhjQlxctjfgdCmnT7iu7Lg iat-mode=0", qrCodeText: "" },
{fingerprint:'8DFC222D2295A909B34B3AAAA584648EE6FAF14D', bridgeline: "obfs4 144.31.125.189:2063 8DFC222D2295A909B34B3AAAA584648EE6FAF14D cert=3BPE8q1dHF1AWoqsQEDGZHrRXPw/AaTwyM7YLGMOfFlxY6qRAlW1Jq0LlzKbe4Gh9+SacA iat-mode=0", qrCodeText: "" },
{fingerprint: '0C6DDE3F9FC377A5E69DC044E81C857277148D71', bridgeline: "obfs4 62.224.107.157:443 0C6DDE3F9FC377A5E69DC044E81C857277148D71 cert=6vp+cyZmJOp+QFtytv9Ca+Z+ASF4l7r12MeEevvufl4OcDimBhjQlxctjfgdCmnT7iu7Lg iat-mode=0", qrCodeText: ""},
{fingerprint:'8DFC222D2295A909B34B3AAAA584648EE6FAF14D', bridgeline: "obfs4 144.31.125.189:2063 8DFC222D2295A909B34B3AAAA584648EE6FAF14D cert=3BPE8q1dHF1AWoqsQEDGZHrRXPw/AaTwyM7YLGMOfFlxY6qRAlW1Jq0LlzKbe4Gh9+SacA iat-mode=0", qrCodeText: ""},
];
function makeQRCodeText(bridgeline: string) {
return '["' + bridgeline + '"]';
}
bridgeLines.forEach((line) => {line.qrCodeText = makeQRCodeText(line.bridgeline)});
console.log(bridgeLines);
const { token } = useToken();
const [searchText, setSearchText] = useState('');
const [searchedColumn, setSearchedColumn] = useState('');
const searchInput = useRef<InputRef>(null);
const handleSearch = (
selectedKeys: string[],
confirm: FilterDropdownProps['confirm'],
dataIndex: DataIndex,
) => {
confirm();
setSearchText(selectedKeys[0]);
setSearchedColumn(dataIndex);
};
const handleReset = (clearFilters: () => void) => {
clearFilters();
setSearchText('');
};
type DataIndex = keyof BridgeDataType;
const getColumnSearchProps = (dataIndex: DataIndex): TableColumnType<BridgeDataType> => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => (
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}>
<Input
ref={searchInput}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={(e) => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => handleSearch(selectedKeys as string[], confirm, dataIndex)}
style={{ marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys as string[], confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => clearFilters && handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
<Button
type="link"
size="small"
onClick={() => {
confirm({ closeDropdown: false });
setSearchText((selectedKeys as string[])[0]);
setSearchedColumn(dataIndex);
}}
>
Filter
</Button>
<Button
type="link"
size="small"
onClick={() => {
close();
}}
>
close
</Button>
</Space>
</div>
),
filterIcon: (filtered: boolean) => (
<SearchOutlined style={{ color: filtered ? '#1677ff' : undefined }} />
),
onFilter: (value, record) =>
record[dataIndex]
.toString()
.toLowerCase()
.includes((value as string).toLowerCase()),
filterDropdownProps: {
onOpenChange(open) {
if (open) {
setTimeout(() => searchInput.current?.select(), 100);
}
},
},
render: (text) =>
searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[searchText]}
autoEscape
textToHighlight={text ? text.toString() : ''}
/>
) : (
text
),
});
const bridgesColumns: TableColumnsType<BridgeDataType> = [
{title: 'Fingerprint',
dataIndex: 'fingerprint',
key: 'fingerprint',
width: '30%',
...getColumnSearchProps('fingerprint')},
{title: 'Bridgeline',
dataIndex: 'bridgeline',
key: 'bridgeline',
width: '40%',
...getColumnSearchProps('bridgeline')},
{title: 'QR Code',
width: '40%',
key: 'qrCodeText',
dataIndex: 'qrCodeText',
render: (text, record) => {return (<QRCode value={record.qrCodeText} />)}
},
]
return(
<>
<Table<BridgeDataType> columns={bridgesColumns} dataSource={bridgeLines} />;
</>);
}
export default Bridges;

View file

@ -1,25 +1,24 @@
// src/Posts.jsx // src/Posts.jsx
import {useUserContext} from './UserContext'; import {useUserContext} from './hooks/UserContext.ts';
import { Button, Form, Input } from 'antd'; import { Button, Form, Input } from 'antd';
//import React, {useEffect, useState} from "react"; //import React, {useEffect, useState} from "react";
import {useAuth} from "react-oidc-context"; import {useAuth} from "react-oidc-context";
import {RefreshContext} from "./hooks/RefreshContext.ts";
import {useContext} from "react";
const CreateOrg = () => { const CreateOrg = () => {
const { currentUser } = useUserContext(); const { currentUser } = useUserContext();
const [form] = Form.useForm(); const [form] = Form.useForm();
const auth = useAuth(); const auth = useAuth();
const { refreshKey, setRefreshKey } = useContext(RefreshContext);
console.log(refreshKey);
async function submitOrgData(values: FormData) { async function submitOrgData(values: FormData) {
if (!auth.user) { if (!auth.user) {
return return
} }
try { try {
console.log("in here");
const [name, q1, q2, q3] = Object.values(values); const [name, q1, q2, q3] = Object.values(values);
console.log("end here");
const data = { const data = {
"name": name, "name": name,
"intake_questionnaire": { "intake_questionnaire": {
@ -28,16 +27,18 @@ const CreateOrg = () => {
"question_three": q3, "question_three": q3,
} }
} }
console.log(data)
const token = auth.user.access_token; const token = auth.user.access_token;
const requestOptions = { const requestOptions = {
method: 'POST', method: 'POST',
body: JSON.stringify(data), body: JSON.stringify(data),
headers: {Authorization: `Bearer ${token}`, headers: {Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'} 'Content-Type': 'application/json'}
} }
const response = await fetch("/api/v1/org/", requestOptions); const response = await fetch("/api/v1/org", requestOptions);
await response.json(); await response.json();
setRefreshKey(prev => prev + 1);
console.log(refreshKey);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
@ -55,29 +56,29 @@ const CreateOrg = () => {
return ( return (
<> <>
<Form <Form
layout= "vertical" layout= "vertical"
form={form} form={form}
onFinish={onFinish} onFinish={onFinish}
> >
<Form.Item name="Organisation name" label="Organisation name" rules={[{ required: true }]}> <Form.Item name="Organisation name" label="Organisation name" rules={[{ required: true }]}>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item name="Question 1" label="How does your organisation support civil society?"> <Form.Item name="Question 1" label="How does your organisation support civil society?">
<Input placeholder="e.g., Our organisation supports various groups such as ..." /> <Input placeholder="e.g., Our organisation supports various groups such as ..." />
</Form.Item> </Form.Item>
<Form.Item name="Question 2" label="Name your first reference"> <Form.Item name="Question 2" label="Name your first reference">
<Input placeholder="e.g., SR2 Communciations Limited" /> <Input placeholder="e.g., SR2 Communciations Limited" />
</Form.Item> </Form.Item>
<Form.Item name="Question 3" label="Name your second reference"> <Form.Item name="Question 3" label="Name your second reference">
<Input placeholder="e.g., SR2 Professional Services" /> <Input placeholder="e.g., SR2 Professional Services" />
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>
<Button type="primary" htmlType="submit">Submit</Button> <Button type="primary" htmlType="submit">Submit</Button>
</Form.Item> </Form.Item>
</Form> </Form>
</> </>
); );
}; };

View file

@ -1,25 +0,0 @@
import React, { createContext, useContext } from 'react';
interface orgObject {
name: string;
status: "partial",
root_user: "string",
owner_contact: "string",
billing_contact: "string",
security_contact: "string"
}
export interface OrgContextType {
currentOrg: orgObject;
setCurrentOrg: React.Dispatch<React.SetStateAction<orgObject>>;
}
export const OrgContext = createContext<OrgContextType | undefined>(undefined);
export const useOrgContext = () => {
const context: OrgContextType | undefined = useContext(OrgContext);
if (context === undefined) {
throw new Error('Organisation context not found');
}
return context;
};

76
src/OrgPanel.tsx Normal file
View file

@ -0,0 +1,76 @@
import {Button, Card, Space} from 'antd';
import type {OrgObject} from "./hooks/OrgContext.ts";
import {useUserContext} from "./hooks/UserContext.ts";
import {useAuth} from "react-oidc-context";
import {useContext} from "react";
import {RefreshContext} from "./hooks/RefreshContext.ts";
const OrgPanel = (props: OrgObject) => {
const auth = useAuth();
const { refreshKey, setRefreshKey } = useContext(RefreshContext);
const {currentUser} = useUserContext();
async function removeUserFromOrg(org_id: number) {
if (!auth.user) {
return
}
try {
const token = auth.user.access_token;
const requestOptions = {
method: 'DELETE',
headers: {Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'}
}
const response = await fetch("/api/v1/org/user?org_id=" + org_id + "&user_id=" + currentUser.id, requestOptions);
await response.json();
setRefreshKey(prev => prev + 1);
console.log(refreshKey)
} catch (e) {
console.error(e);
}
}
async function removeOrg(org_id: number) {
if (!auth.user) {
return
}
try {
const token = auth.user.access_token;
const requestOptions = {
method: 'DELETE',
headers: {Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'}
}
await fetch("/api/v1/org/self?org_id=" + org_id, requestOptions);
setRefreshKey(prev => prev + 1);
console.log(refreshKey)
} catch (e) {
console.error(e);
}
}
return (
<Space vertical size={16}>
<Card title={props.name} extra={<a href="#">More</a>} style={{width: 300}}>
<p>Validated? {props.status}</p>
<p>Root User: {props.root_user_email}</p>
<p>Billing Contact: {props.billing_contact?.email || 'Not set'}</p>
<h3>Questionnaire</h3>
<p>Q1: {props.intake_questionnaire?.question_one || 'Not set'}</p>
<p>Q2: {props.intake_questionnaire?.question_two || 'Not set'}</p>
<p>Q3: {props.intake_questionnaire?.question_three || 'Not set'}</p>
<Button type="primary" onClick={() => removeUserFromOrg(props.organisation_id)}>
Remove yourself from organisation
</Button>
<Button type="primary" danger onClick={() => removeOrg(props.organisation_id)}>
Remove organisation
</Button>
</Card>
</Space>
);
}
export default OrgPanel;

51
src/Organisations.tsx Normal file
View file

@ -0,0 +1,51 @@
import React, {useState} from "react";
import OrgPanel from "./OrgPanel";
import {useAuth} from "react-oidc-context";
import type {OrgObject} from "./hooks/OrgContext.ts";
import type { JSX } from "react/jsx-runtime";
import CreateOrg from "./CreateOrg.tsx";
import {useRefreshContext} from "./hooks/RefreshContext.ts";
const Organisations: React.FC = () => {
const auth = useAuth();
const [orgData, setCurrentOrgData] = useState<OrgObject[]>();
const { refreshKey } = useRefreshContext();
React.useEffect(() => {
const fetchOrgData = async () => {
console.log("Fetching org data");
if (!auth.user) return
try {
const requestOptions = {
method: 'GET',
headers: {
Authorization: `Bearer ${auth.user.access_token}`,
'Content-Type': 'application/json'
}
}
const response = await fetch("/api/v1/user/self/orgs", requestOptions);
const orgsObject = await response.json();
setCurrentOrgData(orgsObject['organisations'])
} catch (e) {
console.error(e);
}
}
fetchOrgData()
.catch(console.error);
}, [auth.user, refreshKey]);
console.log(orgData);
let panels: JSX.Element[] = [];
if (orgData) {
panels = orgData.map(org => <OrgPanel {...org} key={org.organisation_id} />);
}
return(<>
<h1>Your organisations</h1>
{panels}
<h1>Add a new organisation</h1>
<CreateOrg></CreateOrg>
</>);
}
export default Organisations;

View file

@ -1,15 +1,14 @@
import {Breadcrumb, theme} from "antd"; import {Breadcrumb, theme} from "antd";
import React, {useContext} from "react"; import React from "react";
//import {useOrgContext} from './OrgContext'; //import {useOrgContext} from './OrgContext';
import CreateOrg from "./CreateOrg.tsx"; import CreateOrg from "./CreateOrg.tsx";
import {useUserContext} from "./UserContext.tsx"; import {useUserContext} from "./hooks/UserContext.ts";
const Home: React.FC = () => { const Home: React.FC = () => {
const { const {
token: { colorBgContainer, borderRadiusLG }, token: { colorBgContainer, borderRadiusLG },
} = theme.useToken(); } = theme.useToken();
//const { currentOrg } = useOrgContext();
const { currentUser } = useUserContext(); const { currentUser } = useUserContext();
console.log(currentUser.organisations); console.log(currentUser.organisations);
if (currentUser.organisations.length === 0) { if (currentUser.organisations.length === 0) {
@ -19,8 +18,9 @@ const Home: React.FC = () => {
</> </>
} }
//TODO: fix this breadcrumb
return (<> return (<>
<Breadcrumb style={{ margin: '16px 0' }} items={[{ title: 'User' }, { title: 'Bill' }]} /> <Breadcrumb style={{ margin: '16px 0' }} items={[{ title: 'User' }, { title: 'Dashboard' }]} />
<div <div
style={{ style={{
padding: 24, padding: 24,
@ -29,7 +29,8 @@ const Home: React.FC = () => {
borderRadius: borderRadiusLG, borderRadius: borderRadiusLG,
}} }}
> >
Bill is a cat. <h1>Welcome to your dashboard, {currentUser.first_name}!</h1>
</div> </div>
</>) </>)
} }

36
src/hooks/OrgContext.ts Normal file
View file

@ -0,0 +1,36 @@
import React, {createContext, useContext} from 'react';
export interface Contact {
email: string;
id: number;
}
export interface OrgObject {
name: string,
status: "partial",
root_user_email: string,
billing_contact: Contact,
owner_contact: Conotact,
security_contact:Cntact,
organisation_id: number,
intake_questionnaire: {
question_one: string,
question_two: string,
question_three: string
},
}
export interface OrgContextType {
currentOrg: OrgObject;
setCurrentOrg: React.Dispatch<React.SetStateAction<OrgObject>>;
}
export const OrgContext = createContext<OrgContextType | undefined>(undefined);
export const useOrgContext = () => {
const context: OrgContextType | undefined = useContext(OrgContext);
if (context === undefined) {
throw new Error('Organisation context not found');
}
return context;
};

View file

@ -0,0 +1,19 @@
import React, {createContext, useContext} from 'react';
export interface RefreshType {
refreshKey: number;
setRefreshKey: React.Dispatch<React.SetStateAction<number>>;
}
export const RefreshContext = createContext<RefreshType>({
refreshKey: 1,
setRefreshKey: () => {},
});
export const useRefreshContext = () => {
const context: RefreshType | undefined = useContext(RefreshContext);
if (context === undefined) {
throw new Error('Organisation refresh context not found');
}
return context;
};

View file

@ -5,7 +5,8 @@ export interface userObject {
first_name: string; first_name: string;
last_name: string; last_name: string;
email: string; email: string;
organisations: string[]; organisations: { name: string, id: number }[];
id: number;
} }
export interface UserContextType { export interface UserContextType {
@ -21,4 +22,6 @@ export const useUserContext = () => {
throw new Error('User context not found!'); throw new Error('User context not found!');
} }
return context; return context;
}; };

View file

@ -1,6 +1,6 @@
// src/Posts.jsx // src/Posts.jsx
import {useUserContext} from './UserContext'; import { useUserContext} from './hooks/UserContext.ts';
const Profile = () => { const Profile = () => {
const { currentUser } = useUserContext(); const { currentUser } = useUserContext();
@ -8,14 +8,15 @@ const Profile = () => {
if (!currentUser) { if (!currentUser) {
return <div>Loading...</div>; return <div>Loading...</div>;
} }
console.log(currentUser);
console.log(currentUser.organisations);
const userOrgs: { name: string, id: number }[] = currentUser.organisations;
return ( return (
<> <>
<p>User: {currentUser.first_name} {currentUser.last_name}</p> <p>User: {currentUser.first_name} {currentUser.last_name}</p>
<p>Email: {currentUser.email}</p> <p>Email: {currentUser.email}</p>
<p>Orgs: {currentUser.organisations}</p> <p>Current Orgs: {userOrgs[0].name}</p>
</> </>
); );
}; };