Introducing Boards.
Our Slack integration for keeping our clients inspired.
The idea
We wanted a method to keep our clients updated with the best ideas, trends and design work. But we didn't want to make it a chore to update so when time is tight and deadlines are looming it doesn't get forgotten about. Like a lot of design studios, we live in Slack and regularly share pieces of work that have caught our eye with the rest of the team. So in a bid to minimise any additional work, we decided the method of sharing stuff had to be inside Slack.
How it works
Use the shortcut menu and select Add to board
Populate the Modal with all the relevant content selecting which boards you want to add it to
Hit the Submit button
Wait to be updated in Slack
How we built it
To make the build as efficient as possible we decided to stick to as many of our usual tools as possible, so we decided to combine Slack with a Nextjs app, DatoCMS to store the boards and hosted it on Netlify.
After a bit of back and forth with the Slack documentation, some permissions changes and a failed attempt to get ChatGPT to write it for us, we created a Next.js function that handles the Slack event where board_add
is the name we have to the shortcut action.
import { NextResponse } from 'next/server';
import extractUrls from 'extract-urls';
export async function POST(request: Request, response:Response) {
const data = await request.formData();
const payload = data.get("payload") as string;
if(payload){
const json = JSON.parse(payload);
if(json.type === 'message_action' && json.callback_id === 'board_add'){
//do something here
}
}
return NextResponse.json({
"response_action": "clear"
}, {status: 200});
}
We realised the app can't access images added to a channel where the app hasn't been added, so we wrote a little check for that:
export const isUserInChannel = async (channelId: string, username: string):Promise<boolean> => {
const user = await getUserByName(username);
if(!user) return false;
const members = await getChannelMembers(channelId);
return members.includes(user.id);
}
export const getAllUsers = async () => {
const response = await axios({
url:"https://slack.com/api/users.list",
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`
}
});
return response.data.members;
}
export const getUserByName = async (name: string) => {
const users = await getAllUsers();
return users.find((user: { name: string; }) => user.name === name);
}
export const getChannelMembers = async (channelId: string) => {
const response = await axios({
url:"https://slack.com/api/conversations.members",
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`
},
params: {
channel: channelId
}
});
return response.data.members || [];
}
Slack's 3-second rule, where you have to respond within 3 seconds posed a bit of an issue. Downloading an image from Slack and uploading it to DatoCMS was definitely not going to happen in 3-seconds. So to solve this we made use of Netlify's background functions to write a function that could run in the background and keep the user updated on its progress in Slack using response_url
.
Information
Author
Fraser Hobbs
About OHMY
OHMY is a design and technology studio that builds brands and digital products. We help established businesses and startups to give meaningful answers to their most challenging questions.