8000 feat: public profiles for users and organisations by 16-karan · Pull Request #276 · credebl/studio · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: public profiles for users and organisations #276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion src/api/organization.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { axiosGet, axiosPost, axiosPut } from "../services/apiRequests"
import { axiosGet, axiosPost, axiosPublicUserGet, axiosPut } from "../services/apiRequests"

import { apiRoutes } from "../config/apiRoutes";
import { getFromLocalStorage } from "./Auth";
Expand Down Expand Up @@ -302,4 +302,44 @@ export const createConnection = async (orgName: string) => {
}
}

// public profile

export const getPublicUsers = async (pageNumber: number, pageSize: number, search :string) => {

const url = `${apiRoutes.public.users}?pageNumber=${pageNumber}&pageSize=${pageSize}&search=${search}`

const axiosPayload = {
url,
}

try {
return await axiosPublicUserGet(axiosPayload);
}
catch (error) {
const err = error as Error
return err?.message
}
}

export const getPublicOrganizations = async (pageNumber: number, pageSize: number, search :string) => {

const url = `${apiRoutes.public.organizations}?pageNumber=${pageNumber}&pageSize=${pageSize}&search=${search}`

const config = {
headers: {
'Content-Type': 'application/json',
}
}
const axiosPayload = {
url,
config
}

try {
return await axiosGet(axiosPayload);
}
catch (error) {
const err = error as Error
return err?.message
}
}
16 changes: 16 additions & 0 deletions src/app/PublicProfileLayout.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
import NavBarSidebar from "./NavBarSidebar.astro";

---

<NavBarSidebar/>
<div class="flex pt-16 overflow-hidden bg-gray-50 dark:bg-gray-900">
<div
id="main-content"
class="relative w-full h-full overflow-y-auto bg-gray-50 lg:ml-64 dark:bg-gray-900 min-h-screen flex justify-between flex-col"
style="min-height: calc(100vh - 64px);"
>
<slot />

</div>
</div>
83 changes: 83 additions & 0 deletions src/components/publicProfile/OrgUserInfoLayout.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
interface UserDetails {
lastName: string;
firstName: string;
email: string;
publicProfile: boolean;
id: number;
username: string;
}
const { orgUsersData } = Astro.props;
---
{orgUsersData &&
<div class="grid lg:grid-cols-2 sm:grid-cols-1 gap-2 rounded">
<div
class="px-6 py-4 col-span-1 bg-gradient-to-r from-white via-white to-gray-50 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-gray-300 dark:focus:ring-gray-800 shadow-lg shadow-gray-500/50 dark:shadow-lg dark:shadow-gray-800/80 rounded-lg"
>
{
orgUsersData &&
orgUsersData?.map((orgUser: UserDetails) => {
return (
<>
<div class=" flex">
{orgUser.firstName &&
<svg
class="w-6 h-6 text-gray-800 dark:text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 20"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 19a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm0 0a8.949 8.949 0 0 0 4.951-1.488A3.987 3.987 0 0 0 11 14H9a3.987 3.987 0 0 0-3.951 3.512A8.948 8.948 0 0 0 10 19Zm3-11a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
/>
</svg>














<div class="font-bold text-xl pl-2 mb-2">
{orgUser.firstName} {orgUser.lastName}
</div>}
</div>

<div class="flex">
{orgUser.email &&
<svg
class="w-6 h-6 text-gray-800 dark:text-white m-0.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 16"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m19 2-8.4 7.05a1 1 0 0 1-1.2 0L1 2m18 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1m18 0v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2"
/>
</svg>
<p class="text-gray-700 text-xl mb-1.5 pl-1">{orgUser.email}</p>
}
</div>
</>
);
})
}
</div>
</div>}
159 changes: 159 additions & 0 deletions src/components/publicProfile/OrganisationPublicProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
'use client';

import { ChangeEvent, useEffect, useState } from 'react';
import { getPublicOrganizations } from '../../api/organization';
import type { AxiosResponse } from 'axios';
import { apiStatusCodes } from '../../config/CommonConstant';
import SearchInput from '../SearchInput';
import { Button, Card, Pagination } from 'flowbite-react';
import CustomSpinner from '../CustomSpinner';
import CustomAvatar from '../Avatar';
import { EmptyListMessage } from '../EmptyListComponent';

const OrganisationPublicProfile = () => {
const initialPageState = {
pageNumber: 1,
pageSize: 10,
total: 0,
};

const [organizationsList, setOrganizationList] = useState([]);

const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [searchText, setSearchText] = useState('');
const [currentPage, setCurrentPage] = useState(initialPageState);
const number) => {
setCurrentPage({
...currentPage,
pageNumber: page,
});
};

const getAllOrganizations = async () => {
setLoading(true);
const response = await getPublicOrganizations(
currentPage?.pageNumber,
currentPage?.pageSize,
searchText,
);

const { data } = response as AxiosResponse;

if (data?.statusCode === apiStatusCodes?.API_STATUS_SUCCESS) {
const totalPages = data?.data?.totalPages;

const orgList = data?.data?.organizations.map((userOrg: any) => {
return userOrg;
});

setOrganizationList(orgList);
setCurrentPage({
...currentPage,
total: totalPages,
});
} else {
setError(response as string);
}
setLoading(false);
};

useEffect(() => {
let getData: NodeJS.Timeout;

if (searchText?.length >= 1) {
getData = setTimeout(() => {
getAllOrganizations();
}, 1000);
} else {
getAllOrganizations();
}

return () => clearTimeout(getData);
}, [searchText, currentPage.pageNumber]);

const searchInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setSearchText(e.target.value);
};

return (
<div>
<div className="flex items-center justify-between mb-4 p-2 pl-0">
<SearchInput />
</div>

<div className="flex flex-wrap">
{loading ? (
<div className="flex items-center justify-center mb-4 ">
<CustomSpinner />
</div>
) : organizationsList && organizationsList?.length > 0 ? (
<div className="mt-1 grid w-full grid-cols-1 gap-4 mt-0 mb-4 xl:grid-cols-2">
{organizationsList?.map(
(org: {
logoUrl: string;
name: string;
description: string;
id: number;
orgSlug: string;
}) => (
<Card
=> {
window.location.href = `/org/${org?.orgSlug}`;
}}
className="transform transition duration-500 hover:scale-[1.02] hover:bg-gray-50 cursor-pointer"
>
<div className="flex items-center">
{org.logoUrl ? (
<CustomAvatar size="80" src={org?.logoUrl} />
) : (
<CustomAvatar size="80" name={org?.name} />
)}

<div className="ml-4">
<h5 className="text-xl font-bold tracking-tight text-gray-900 dark:text-white">
<p>{org?.name}</p>
</h5>
<div className="flow-root h-auto">
<ul className="divide-y divide-gray-200 dark:divide-gray-700">
<li className="py-3 sm:py-4 overflow-auto">
<div className="flex items-center space-x-4">
<div className="inline-flex items-center text-base text-lg text-gray-900 dark:text-white">
{org?.description}
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</Card>
),
)}
</div>
) : (
organizationsList && (
<div className="flex justify-center items-center">
<EmptyListMessage
message={'No Matching Organization'}
description={''}
/>
</div>
)
)}

<div className="flex items-center justify-end mb-4">
{organizationsList && organizationsList?.length > 0 && (
<Pagination
currentPage={currentPage?.pageNumber}
>
totalPages={currentPage?.total}
/>
)}
</div>
</div>
</div>
);
};

export default OrganisationPublicProfile;
30 changes: 30 additions & 0 deletions src/components/publicProfile/ProfileDesign.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
const {orgData} = Astro.props
import CustomAvatar from "../../components/Avatar"
---


<div class="min-[320]:h-auto md:h-screen col-span-1 border-white box-border">
<div class="w-full h-full bg-white rounded-lg shadow dark:bg-gray-800 dark:border-gray-700 ">
<div class="flex flex-col items-center pb-10">

{orgData?.logoUrl ? (
<CustomAvatar className="my-4 rounded-full shadow-lg" size="100" src={orgData?.logoUrl} client:load />
) : (
<CustomAvatar className="my-4 rounded-full shadow-lg" size="180" name={orgData?.name} client:load />
)}

<h3 class="mb-1 text-3xl font-medium text-gray-900 dark:text-white pt-4">{orgData?.name}</h3>
<div class="flex text-center align-middle ">
{orgData?.website &&
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 19 19">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.013 7.962a3.519 3.519 0 0 0-4.975 0l-3.554 3.554a3.518 3.518 0 0 0 4.975 4.975l.461-.46m-.461-4.515a3.518 3.518 0 0 0 4.975 0l3.553-3.554a3.518 3.518 0 0 0-4.974-4.975L10.3 3.7"/>
</svg>
<a href={orgData?.website}> <span class="text-2xl text-gray-500 dark:text-gray-400 pl-2 ">{orgData?.website}</span></a>
}
</div>
<p class="pt-2 p-4 flex items-center justify-center flex-wrap">{orgData?.description}</p>
</div>
</div>
</div>

Loading
0