first working attestation prototype

This commit is contained in:
Anton Tranelis 2024-07-31 09:25:14 +02:00
parent 4f92c5b4b4
commit bc8b73451c
4 changed files with 103 additions and 115 deletions

View File

@ -2,7 +2,7 @@ import { MapOverlayPage } from '../Templates'
import { useItems, useRemoveItem, useUpdateItem } from '../Map/hooks/useItems'
import { useLocation, useNavigate } from 'react-router-dom'
import { useEffect, useState } from 'react';
import { Item, Tag } from '../../types';
import { Item, ItemsApi, Tag } from '../../types';
import { useMap } from 'react-leaflet';
import { LatLng } from 'leaflet';
import { useHasUserPermission } from '../Map/hooks/usePermissions';
@ -17,7 +17,7 @@ import { SimpleView } from './Templates/SimpleView';
import { handleDelete, linkItem, unlinkItem } from './itemFunctions';
import { useTags } from '../Map/hooks/useTags';
export function ProfileView({ userType }: { userType: string }) {
export function ProfileView({ userType, attestationApi }: { userType: string , attestationApi?: ItemsApi<any>}) {
const [item, setItem] = useState<Item>({} as Item)
const [updatePermission, setUpdatePermission] = useState<boolean>(false);
@ -40,6 +40,23 @@ export function ProfileView({ userType }: { userType: string }) {
const clusterRef = useClusterRef();
const leafletRefs = useLeafletRefs();
const [attestations, setAttestations] = useState<Array<any>>([]);
useEffect(() => {
if (attestationApi) {
attestationApi.getItems()
.then(value => {
console.log(value);
setAttestations(value);
})
.catch(error => {
console.error("Error fetching items:", error);
});
}
}, [attestationApi])
useEffect(() => {
const itemId = location.pathname.split("/")[2];
const item = items.find(i => i.id === itemId);
@ -140,7 +157,7 @@ export function ProfileView({ userType }: { userType: string }) {
}
{template == "tabs" &&
<TabsView setUrlParams={setUrlParams} item={item} loading={loading} offers={offers} needs={needs} relations={relations} updatePermission={updatePermission} linkItem={(id) => linkItem(id, item, updateItem)} unlinkItem={(id) => unlinkItem(id, item, updateItem)}/>
<TabsView userType={userType} attestations={attestations} setUrlParams={setUrlParams} item={item} loading={loading} offers={offers} needs={needs} relations={relations} updatePermission={updatePermission} linkItem={(id) => linkItem(id, item, updateItem)} unlinkItem={(id) => unlinkItem(id, item, updateItem)}/>
}
</>

View File

@ -6,8 +6,12 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import { useAddFilterTag } from '../../Map/hooks/useFilter'
import { Item, Tag } from 'utopia-ui/dist/types'
import { useNavigate } from 'react-router-dom'
import { useItems } from '../../Map/hooks/useItems'
import { useAssetApi } from '../../AppShell/hooks/useAssets'
import { timeAgo } from '../../../Utils/TimeAgo'
import { useAuth } from '../../Auth'
export const TabsView = ({ item, offers, needs, relations, updatePermission, loading, linkItem, unlinkItem, setUrlParams }: { item: Item, offers: Array<Tag>, needs: Array<Tag>, relations: Array<Item>, updatePermission: boolean, loading: boolean, linkItem: (id: string) => Promise<void>, unlinkItem: (id: string) => Promise<void> , setUrlParams: any}) => {
export const TabsView = ({ attestations, userType, item, offers, needs, relations, updatePermission, loading, linkItem, unlinkItem, setUrlParams }: { attestations: Array<any>, userType: string, item: Item, offers: Array<Tag>, needs: Array<Tag>, relations: Array<Item>, updatePermission: boolean, loading: boolean, linkItem: (id: string) => Promise<void>, unlinkItem: (id: string) => Promise<void>, setUrlParams: any }) => {
const addFilterTag = useAddFilterTag();
const [activeTab, setActiveTab] = useState<number>();
@ -15,12 +19,20 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
const [addItemPopupType, setAddItemPopupType] = useState<string>("");
const items = useItems();
const assetsApi = useAssetApi();
const {user} = useAuth();
const getUserProfile = (id: string) => {
return items.find(i => i.user_created.id === id && i.layer?.itemType.name === userType)
}
useEffect(() => {
scroll();
scroll();
}, [addItemPopupType])
function scroll() {
tabRef.current?.scrollIntoView();
tabRef.current?.scrollIntoView();
}
const tabRef = useRef<HTMLFormElement>(null);
@ -42,57 +54,6 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
setActiveTab(urlTab ? Number(urlTab) : 1);
}, [location.search]);
const attestations = [{
from: "Timo",
avatar: "https://api.utopia-lab.org/assets/262117f8-feb6-444f-9bd2-e84087285760?width=80&heigth=80",
symbol: "🥇",
text: "1. Platz im Bogenschießen",
date: "21.06.2024",
},
{
from: "Sebastian",
avatar: "https://api.utopia-lab.org/assets/7510a082-882b-41c3-aa7d-5a19f9502f25?width=80&heigth=80",
symbol: "🌱",
text: "danke fürs Rasen mähen",
date: "29.06.2024",
},
{
from: "Yurij",
avatar: "https://api.utopia-lab.org/assets/abe62291-35ad-45de-b978-e5906d8a3eb6?width=80&heigth=80",
symbol: "🏆",
text: "bester Coder ever",
date: "04.07.2024",
},
{
from: "Luca",
avatar: "https://api.utopia-lab.org/assets/e285e653-36e8-4211-a69d-00053c1f610e?width=80&heigth=80",
symbol: "🙏",
text: "Vielen Dank für deine Hilfe!!!",
date: "04.07.2024",
},
{
from: "Lisa",
avatar: "https://i.pinimg.com/originals/c0/ed/08/c0ed088cd6532d4fd27396aefddac57c.jpg",
symbol: "❤️",
text: "Vielen Dank für deine Hilfe!!!",
date: "04.07.2024",
},
{
from: "Timo",
avatar: "https://api.utopia-lab.org/assets/262117f8-feb6-444f-9bd2-e84087285760?width=80&heigth=80",
symbol: "🥈",
text: "2. Platz im Bogenschießen",
date: "21.06.2024",
},
{
from: "Anton",
avatar: "https://api.utopia-lab.org/assets/007dc678-6073-4ad1-9b47-f2cfe1dca582?width=80&heigth=80",
symbol: "🌱",
text: "danke fürs Rasen mähen",
date: "29.06.2024"
},
]
return (
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2 tw-px-6">
<input type="radio" name="my_tabs_2" role="tab"
@ -106,53 +67,58 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
}
<TextView item={item} />
<div className='tw-h-4'></div>
<TextView item={item} itemTextField='contact'/>
<TextView item={item} itemTextField='contact' />
</div>
{item.layer?.itemType.questlog &&
<>
<input type="radio" name="my_tabs_2" role="tab"
className={`tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]`}
aria-label="❤️" checked={activeTab == 2 && true}
onChange={() => updateActiveTab(2)} />
<>
<input type="radio" name="my_tabs_2" role="tab"
className={`tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]`}
aria-label="❤️" checked={activeTab == 2 && true}
onChange={() => updateActiveTab(2)} />
<div role="tabpanel"
className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-4 tw-mb-4 tw-overflow-x-hidden">
<table className="sm:tw-table-sm md:tw-table-md">
<tbody>
{attestations.map((a, i) => <tr key={i}>
<td>
<div className='tw-mask tw-mask-circle tw-text-xl md:tw-text-2xl tw-bg-slate-200 tw-rounded-full tw-p-2 tw-my-1 tw-mr-2'>{a.symbol}</div>
</td>
<td>
<div className='tw-mr-2' ><i>{a.text}</i></div>
</td>
<td>
<div className="flex items-center gap-3">
<div className="tw-avatar">
<div className="tw-mask tw-rounded-full h-8 w-8 tw-mr-2">
<img
src={a.avatar}
alt="Avatar Tailwind CSS Component" />
</div>
</div>
<div>
<div className="font-bold">{a.from}</div>
<div className="tw-text-xs opacity-50 tw-text-zinc-500">{a.date}</div>
</div>
</div>
</td>
</tr>)}
</tbody>
</table>
<div role="tabpanel"
className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-4 tw-mb-4 tw-overflow-x-hidden">
<table className="sm:tw-table-sm md:tw-table-md">
<tbody>
{attestations.filter(a => a.to.some(t => t.directus_users_id == item.user_created.id)).map((a, i) => <tr key={i}>
<td>
<div
className={`tw-cursor-pointer tw-text-3xl tw-mask tw-mask-${a.shape} tw-p-3 tw-mr-2 tw-bg-[${a.color}]`}
>
{a.emoji}
</div>
</>
}
</td>
<td>
<div className='tw-mr-2' ><i>{a.text}</i></div>
</td>
<td>
<div className="flex items-center gap-3">
<div className="tw-avatar">
<div className="tw-mask tw-rounded-full h-8 w-8 tw-mr-2">
<img
src={assetsApi.url + getUserProfile(a.user_created.id)?.image}
alt="Avatar Tailwind CSS Component" />
</div>
</div>
<div>
<div className="font-bold">{getUserProfile(a.user_created.id)?.name}</div>
<div className="tw-text-xs opacity-50 tw-text-zinc-500">{timeAgo(a.date_created)}</div>
</div>
</div>
</td>
</tr>)}
</tbody>
</table>
</div>
</>
}
{item.layer?.itemType.offers_and_needs &&
<>

View File

@ -3,16 +3,17 @@ import { MapOverlayPage } from './MapOverlayPage'
import { useItems } from '../Map/hooks/useItems'
import { useAssetApi } from '../AppShell/hooks/useAssets'
import { EmojiPicker } from './EmojiPicker';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import { useRef, useState } from 'react';
import { Item, ItemsApi } from '../../types';
import { useEffect } from 'react';
export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
export const AttestationForm = ({api}:{api?:ItemsApi<any>}) => {
const items = useItems();
const assetsApi = useAssetApi();
const [users, setUsers] = useState<Array<Item>>();
const navigate = useNavigate();
useEffect(() => {
let params = new URLSearchParams(location.search);
@ -35,16 +36,22 @@ export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
};
const sendAttestation = async () => {
api.createItem && api.createItem({
const to : Array<any> = [];
users?.map(u => to.push({ directus_users_id: u.user_created.id }));
console.log(to);
api?.createItem && api.createItem({
text: inputValue,
symbol: "🔥",
color: "",
shape: "",
to: users
})
emoji: selectedEmoji,
color: selectedColor,
shape: selectedShape,
to: to
}).then(()=> navigate("/"))
}
const [selectedEmoji, setSelectedEmoji] = useState('select badge');
const [selectedShape, setSelectedShape] = useState('circle');
const [selectedColor, setSelectedColor] = useState('#fff0d6');
return (
@ -70,7 +77,7 @@ export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
<div className='tw-w-full'>
<div className='tw-flex tw-justify-center tw-items-center'>
<div className=' tw-flex tw-justify-center tw-items-center tw-w-28 tw-h-28 tw-m-4'>
<EmojiPicker />
<EmojiPicker selectedEmoji={selectedEmoji} selectedColor={selectedColor} selectedShape={selectedShape} setSelectedEmoji={setSelectedEmoji} setSelectedColor={setSelectedColor} setSelectedShape={setSelectedShape} />
</div>
</div>
<div className='tw-flex tw-justify-center tw-items-center'>
@ -82,7 +89,7 @@ export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
className="tw-input tw-min-w-0 tw-w-fit tw-resize-none tw-overflow-hidden tw-text-center " />
</div>
</div>
<div className='tw-w-full tw-grid tw-mt-4'><Link className="tw-place-self-center" to="/item/b42a1404-fe08-4d84-8404-47ce623c3cf2?tab=2"><button className="tw-btn tw-px-8">Next</button></Link></div>
<div className='tw-w-full tw-grid tw-mt-4'><button onClick={sendAttestation} className="tw-btn tw-place-self-center tw-px-8">Next</button></div>
</MapOverlayPage>
)
}

View File

@ -1,9 +1,7 @@
import { useState } from 'react';
export const EmojiPicker = () => {
const [selectedEmoji, setSelectedEmoji] = useState('select badge');
const [selectedShape, setSelectedShape] = useState('circle');
const [selectedColor, setSelectedColor] = useState('#fff0d6');
export const EmojiPicker = ({selectedEmoji, selectedColor, selectedShape, setSelectedEmoji, setSelectedColor, setSelectedShape}) => {
const [isOpen, setIsOpen] = useState(false);