Latio Team: A community for tech hackers building together
Freddy González
Posted on October 28, 2024
This is a submission for the Wix Studio Challenge: Community Edition.
My Community Platform
Latio Team is a community built for tech builders based in LATAM, it's a place to interact, learn, grow, and connect together while participating at hackathons. The community page includes the next features:
- A talent pool: members get their profile listed on a public page which aims to be seen by recruiters or other entrepreneurs.
- Job opportunities: a job board that showcases the latest remote jobs for our members (API provided by RemoteOK), members can see and apply to job posts within the community page.
- Hackathon Listings: the place to share and post new hackathon opportunities for our members.
- Connect: a space to talk with other members, post work updates, and also find new collaborators.
- Work Inquiries: each member profile features a contact button where recruiters can send them a message or ask for a work inquiry. Members then can see the received messages inside a custom listing page without having to expose their private details.
Demo
Project link: https://fredoist.wixstudio.io/latio-team
Work Inquiry form and listings:
Development Journey
Building with Wix's Studio and Velo API's was quite easy if you already know JavaScript.
All the documentation for Velo APIs is clear and very complete, also, the editor inside Wix Studio has some great autocomplete features which made very easy to use. Once you start building and testing the editor you understand how it works and you can implement new APIs quickly.
As an additional point, Wix's templates let you build a stunning website very fast, the design adapts to each new App for element you add which it's pretty cool since you don't need to touch anything else.
This is the code blocks for some of the features so you can replicate them:
Job postings
import { Permissions, webMethod } from "wix-web-module";
import { getJSON } from "wix-fetch";
const formatPrice = (p) =>
new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: p < 1 ? 3 : 1,
}).format(Number(p));
// GET call using getJSON
export const getJobs = webMethod(Permissions.Anyone, async () => {
const response = await getJSON(
"https://remoteok.com/api",
);
const jobs = response.slice(1).map(job => {
job._id = job.id;
job.salary_range = `\$ ${formatPrice(job.salary_min)}-${formatPrice(job.salary_max)}`
job.company_logo = job.company_logo ? `https://remoteok.com/cdn-cgi/image/format=auto,fit=contain,width=100,height=100,quality=50/${job.company_logo}` : null;
job.logo = job.logo ? `https://remoteok.com/cdn-cgi/image/format=auto,fit=contain,width=100,height=100,quality=50/${job.logo}` : null;
job.image = job.company_logo ?? job.logo ?? `https://ui-avatars.com/api/?name=${job.company}`
return job;
})
return jobs;
});
Job page
import { ok, notFound, WixRouterSitemapEntry } from "wix-router";
import { getJobs } from "backend/fetch-jobs.web"
export async function job_Router(request) {
// Get item name from URL request
const slug = request.path[0];
// Get the item data by name
const jobs = await getJobs();
const data = jobs.filter(job => job.slug === slug)
if (data.length) {
const job = data[0];
// Define SEO tags
const seoData = {
title: job.position,
description: "This is a description of " + job.position + " page",
noIndex: false,
metaTags: [{
"property": "og:title",
"content": job.position
}, ]
};
// Render item page
return ok("job-page", job, seoData);
}
// Return 404 if item is not found
return notFound();
}
export async function job_SiteMap(sitemapRequest) {
const jobs = await getJobs()
// Convert the data to site map entries
const siteMapEntries = jobs.map((job) => {
const data = job;
const entry = new WixRouterSitemapEntry(job.slug);
entry.pageName = "job-page"; // The name of the page in the Wix editor to render
entry.url = "/job/" + job.slug; // Relative URL of the page
entry.title = data.position; // For better SEO - Help Google
return entry;
});
// Return the site map entries
return siteMapEntries;
}
Sending inquiries for any member
import { Permissions, webMethod } from "wix-web-module";
import wixData from "wix-data";
export const sendInquiry = webMethod(
Permissions.Anyone,
async (username, email, details, budget) => {
const results = await wixData.query("Members/PrivateMembersData").eq('slug', username).find()
const member = results.items.length > 0 ? results.items[0] : null;
if(member) {
const memberId = member._id;
const result = await wixData.save("WorkInquiries", {
recipientId: memberId,
contactEmail: email,
details,
budget
})
if(result) {
return true
}
}
return false;
}
);
Fetching member inquiries
import { Permissions, webMethod } from "wix-web-module";
import { query } from "wix-data";
import { currentMember } from "wix-members-backend"
export const getInquiries = webMethod(
Permissions.SiteMember,
async () => {
const member = await currentMember.getMember();
const data = await query("WorkInquiries").eq('recipientId', member._id).find();
return data.items;
}
);
Velo APIs
-
wix-data
: it is used to store, fetch, and render custom collections data and also member's data in public/private features. -
wix-fetch
: job posts are provided by RemoteOK's API and these are fetched using Wix's fetching methods, then jobs are rendered into repeaters blocks. -
wix-router
: job posts also are rendered into its own page for which Wix's router is used. -
wix-members-backend
: it is used to link the inquiries form to a custom collection, once data is sent the memberId is retrieved using this API by matching the profile slug, it then is passed to the collection with the form data. -
wix-location-frontend
andwix-window-frontend
: these are simply used to get URL data such as the path or member slug.
Wix Apps
- Wix Members Area: used for user profiles and authentication.
- Wix Groups: used for the connect feature.
- Wix FAQ: to include a FAQ into the homepage.
- CMS: I used some CMS connections to display data inside pages.
Posted on October 28, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.