Skip to content

Commit 621e135

Browse files
committed
add initial version of UI
1 parent 21c278b commit 621e135

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React from 'react';
2+
import { FormTokenField } from '@wordpress/components';
3+
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
4+
import { useSelect, useDispatch, select } from '@wordpress/data';
5+
import { useEffect, useState, useCallback } from '@wordpress/element';
6+
import { store as coreStore, Post } from '@wordpress/core-data';
7+
import { store } from '../store';
8+
import { ContentConnectRelationship } from '../store/types';
9+
import { decodeEntities } from '@wordpress/html-entities';
10+
import apiFetch from '@wordpress/api-fetch';
11+
import { addQueryArgs } from '@wordpress/url';
12+
13+
type RelationshipManagerProps = {
14+
postId: number | null;
15+
relationship: ContentConnectRelationship;
16+
};
17+
18+
export function RelationshipManager({ postId, relationship }: RelationshipManagerProps) {
19+
const { updateRelatedPosts } = useDispatch(store);
20+
const [suggestions, setSuggestions] = useState<string[]>([]);
21+
const [searchTerm, setSearchTerm] = useState('');
22+
const [currentSearch, setCurrentSearch] = useState('');
23+
24+
const { relatedPosts, searchResults } = useSelect((select) => ({
25+
relatedPosts: select(store).getRelatedPosts(postId, {
26+
rel_key: relationship.rel_key,
27+
}),
28+
searchResults: searchTerm ? select(coreStore).getEntityRecords<Post>(
29+
'postType',
30+
relationship.post_type[0],
31+
{
32+
search: searchTerm,
33+
per_page: 20,
34+
orderby: 'title',
35+
order: 'asc',
36+
}
37+
) : [],
38+
}), [postId, relationship.rel_key, relationship.post_type, searchTerm]);
39+
40+
async function getPostByTitle(title: string) {
41+
const result = await apiFetch<{ id: number }[]>({
42+
path: addQueryArgs(`/wp/v2/${relationship.post_type[0]}`, {
43+
search: title,
44+
per_page: 1,
45+
_fields: 'id',
46+
}),
47+
});
48+
return result[0]?.id ?? undefined;
49+
}
50+
51+
// Convert related posts to token format
52+
const tokens = relatedPosts.map((post) => post.name);
53+
54+
// Update suggestions based on search
55+
useEffect(() => {
56+
if (!searchResults) {
57+
setSuggestions([]);
58+
return;
59+
}
60+
61+
const newSuggestions = searchResults
62+
.filter((post) => !relatedPosts.find((related) => related.ID === post.id))
63+
.map((post) => decodeEntities(post.title.rendered));
64+
65+
setSuggestions(newSuggestions);
66+
}, [searchResults, relatedPosts]);
67+
68+
const handleChange = async (newTokens: any[]) => {
69+
const newRelatedIds = await Promise.all(
70+
newTokens.map(async (token) => {
71+
const tokenValue = typeof token === 'string' ? token : token.value;
72+
return getPostByTitle(tokenValue);
73+
})
74+
);
75+
76+
updateRelatedPosts(postId, relationship.rel_key, newRelatedIds.filter((id): id is number => id !== undefined));
77+
};
78+
79+
return (
80+
<PluginDocumentSettingPanel
81+
name={`content-connect-relationship-${relationship.rel_key}`}
82+
title={relationship.labels.name}
83+
>
84+
<FormTokenField
85+
value={tokens}
86+
suggestions={suggestions}
87+
onChange={handleChange}
88+
onInputChange={(input) => setSearchTerm(input)}
89+
label={relationship.labels.name}
90+
__next40pxDefaultSize={true}
91+
__experimentalShowHowTo={false}
92+
/>
93+
</PluginDocumentSettingPanel>
94+
);
95+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import { useSelect } from '@wordpress/data';
3+
import { store as editorStore } from '@wordpress/editor';
4+
import { store } from '../store';
5+
import { RelationshipManager } from './relationship-manager';
6+
7+
export function RelationshipsPanel() {
8+
const { postId, relationships } = useSelect((select) => {
9+
const postId = select(editorStore).getCurrentPostId();
10+
const relationships = select(store).getRelationships(postId);
11+
12+
return {
13+
postId,
14+
relationships,
15+
};
16+
}, []);
17+
18+
if (!relationships || Object.keys(relationships).length === 0) {
19+
return null;
20+
}
21+
22+
return (
23+
<>
24+
{Object.values(relationships).map((relationship) => (
25+
<RelationshipManager
26+
key={relationship.rel_key}
27+
postId={postId}
28+
relationship={relationship}
29+
/>
30+
))}
31+
</>
32+
);
33+
}

assets/js/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
import './store';
22
import './hooks';
3+
4+
import { registerPlugin } from '@wordpress/plugins';
5+
import { RelationshipsPanel } from './components/relationships-panel';
6+
7+
registerPlugin('wp-content-connect', {
8+
render: RelationshipsPanel,
9+
});

0 commit comments

Comments
 (0)