chore: added the ability for recruiter to search skills in the cv page

This commit is contained in:
Andre Henriques 2024-10-06 17:37:49 +01:00
parent 92e3b91176
commit dd9d174449
4 changed files with 143 additions and 42 deletions

View File

@ -4,5 +4,8 @@ spring.datasource.username=applications
spring.datasource.password=applications
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Disable the trace on the error responses
server.error.include-stacktrace=never
# spring.sql.init.schema-locations=classpath:schema.sql
# spring.sql.init.mode=always

View File

@ -3,6 +3,7 @@ package com.andr3h3nriqu3s.applications
import java.sql.ResultSet
import java.util.UUID
import org.springframework.http.MediaType
import org.springframework.http.HttpStatus
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Service
@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
data class CreateFlair(
var color: String,
@ -26,7 +28,11 @@ data class CreateFlair(
@RestController
@ControllerAdvice
@RequestMapping("/api/flair")
class FlairController(val sessionService: SessionService, val flairService: FlairService) {
class FlairController(
val sessionService: SessionService,
val flairService: FlairService,
val applicationService: ApplicationService
) {
@PutMapping(path = ["/"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun create(
@ -61,6 +67,16 @@ class FlairController(val sessionService: SessionService, val flairService: Flai
return flairService.listUser(user)
}
@GetMapping(path = ["/simple/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun listSimple(@PathVariable id: String): List<SimpleFlair> {
var application = applicationService.findApplicationByIdNoUser(id)
if (application == null) {
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Application Not Found", null)
}
return flairService.listUserId(application.user_id).map { it.toFlairSimple() }
}
@DeleteMapping(path = ["/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun delete(@PathVariable id: String, @RequestHeader("token") token: String): Flair {
val user = sessionService.verifyTokenThrow(token)
@ -69,9 +85,9 @@ class FlairController(val sessionService: SessionService, val flairService: Flai
}
data class SimpleFlair(
val name: String,
val description: String,
val color: String,
val name: String,
val description: String,
val color: String,
)
data class Flair(
@ -96,7 +112,7 @@ data class Flair(
}
fun toFlairSimple(): SimpleFlair {
return SimpleFlair(this.name, this.description, this.color);
return SimpleFlair(this.name, this.description, this.color)
}
}
@ -151,7 +167,20 @@ public class FlairService(val db: JdbcTemplate) {
.toList()
public fun listUser(user: UserDb): List<Flair> =
db.query("select * from flair where user_id=? order by name asc;", arrayOf(user.id), Flair).toList()
db.query(
"select * from flair where user_id=? order by name asc;",
arrayOf(user.id),
Flair
)
.toList()
public fun listUserId(id: String): List<Flair> =
db.query(
"select * from flair where user_id=? and description != '' order by name asc;",
arrayOf(id),
Flair
)
.toList()
public fun getById(user: UserDb, id: String): Flair? {
val items =

View File

@ -65,6 +65,7 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
});
async function startup() {
console.log("Exp startup application")
await browser.storage.local.set({
windows: null,
interesetWindows: [],

View File

@ -29,7 +29,7 @@
let application: Application | undefined = $state(undefined);
async function loadData() {
if (!id) return;
if (!id) return;
try {
application = await get(`application/cv/${id}`);
@ -49,20 +49,34 @@
}
return 0;
});
loadFlairs();
} catch (e) {
console.log('TODO show this to the user', e);
}
}
// Other skills search
let otherSearch = $state('');
let flairs: SimpleFlair[] = $state([]);
async function loadFlairs() {
try {
flairs = await get(`flair/simple/${id ?? ''}`);
} catch (e) {
console.log('TODO inform the user', e);
}
}
</script>
<svelte:head>
{#if application && userStore.isLoggedIn}
<title>
andre-henriques-{application.company.toLowerCase().split(' ')[0]}
</title>
{:else}
<title>CV</title>
{/if}
{#if application && userStore.isLoggedIn}
<title>
andre-henriques-{application.company.toLowerCase().split(' ')[0]}
</title>
{:else}
<title>CV</title>
{/if}
</svelte:head>
<div class="flex items-center w-full flex-col">
@ -74,11 +88,17 @@
<div class="text-right">
<ul>
<li class="px-1">
{#if id}
<a class="underline" href="https://www.andr3h3nriqu3s.com/cv?id={id}">andr3h3nriqu3s.com</a>
{:else}
<a class="underline" href="https://www.andr3h3nriqu3s.com/cv">andr3h3nriqu3s.com</a>
{/if}
{#if id}
<a
class="underline"
href="https://www.andr3h3nriqu3s.com/cv?id={id}"
>andr3h3nriqu3s.com</a
>
{:else}
<a class="underline" href="https://www.andr3h3nriqu3s.com/cv"
>andr3h3nriqu3s.com</a
>
{/if}
</li>
<li class="px-1">
<a class="underline" href="mailto:contact@andr3h3nriqu3s.com"
@ -128,36 +148,84 @@
{/if}
{#if application.flairs.length > 0}
<div class="p-3 bg-white w-[190mm] rounded-lg">
<h1>Your Ad & My skills</h1>
<h1 class="flex gap-5 items-end">
Your Ad & My skills {#if flairs.length > 0}<input
placeholder="Loking for other skills search?"
class="flex-grow text-blue-500 print:hidden"
bind:value={otherSearch}
/>
<span class="hidden print:inline text-slate-600 text-sm"><a href="https://www.andr3h3nriqu3s.com/cv?id={id}">Looking for other skills?</a></span>
{/if}
</h1>
<div class="flex flex-wrap gap-2 py-2">
{#each application.flairs as flair}
<div class="min-w-0 {flair.description ? 'flex-grow w-full' : ''}">
{#if flair.description}
<div
class="p-2 rounded-lg forced-color-adjust-none"
style="background: {flair.color};"
>
{#if otherSearch === ''}
{#each application.flairs as flair}
<div class="min-w-0 {flair.description ? 'flex-grow w-full' : ''}">
{#if flair.description}
<div
class="rounded-lg print:p-2 print:inline-block"
class="p-2 rounded-lg forced-color-adjust-none"
style="background: {flair.color};"
>
<div
class="rounded-lg print:p-2 print:inline-block"
style="background: {flair.color}; print-color-adjust: exact !important;"
>
{flair.name}
</div>
<span class="hidden print:inline">:</span>
<div class="bg-white my-1 print:inline p-1 rounded-md">
{flair.description}
</div>
</div>
{:else}
<div
class="p-2 rounded-lg forced-color-adjust-none"
style="background: {flair.color}; print-color-adjust: exact !important;"
>
{flair.name}
</div>
<span class="hidden print:inline">:</span>
<div class="bg-white my-1 print:inline p-1 rounded-md">
{flair.description}
</div>
{/if}
</div>
{/each}
{:else}
{@const filtered_list = flairs.filter((a) =>
a.name.match(new RegExp(otherSearch, 'i'))
)}
{#if filtered_list.length == 0}
<div class="w-full text-center text-blue-500 font-bold text-2xl py-10">
Could not find the skill you are looking for.
</div>
{:else}
{#each filtered_list as flair}
<div class="min-w-0 {flair.description ? 'flex-grow w-full' : ''}">
{#if flair.description}
<div
class="p-2 rounded-lg forced-color-adjust-none"
style="background: {flair.color};"
>
<div
class="rounded-lg print:p-2 print:inline-block"
style="background: {flair.color}; print-color-adjust: exact !important;"
>
{flair.name}
</div>
<span class="hidden print:inline">:</span>
<div class="bg-white my-1 print:inline p-1 rounded-md">
{flair.description}
</div>
</div>
{:else}
<div
class="p-2 rounded-lg forced-color-adjust-none"
style="background: {flair.color}; print-color-adjust: exact !important;"
>
{flair.name}
</div>
{/if}
</div>
{:else}
<div
class="p-2 rounded-lg forced-color-adjust-none"
style="background: {flair.color}; print-color-adjust: exact !important;"
>
{flair.name}
</div>
{/if}
</div>
{/each}
{/each}
{/if}
{/if}
</div>
</div>
{/if}