Skip to content

Commit

Permalink
Add user thumbnails
Browse files Browse the repository at this point in the history
  • Loading branch information
chokoswitch committed Nov 13, 2024
1 parent cca9398 commit b6140d9
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 123 deletions.
Binary file modified api/descriptors/descriptorset.pb
Binary file not shown.
20 changes: 19 additions & 1 deletion api/frontendapi/frontend.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ package frontendapi;

option go_package = "github.com/curioswitch/aiceo/api/go;frontendapi";

// A user gender.
enum Gender {
// Gender has not been set.
GENDER_UNSPECIFIED = 0;

// Male.
GENDER_MALE = 1;

// Female.
GENDER_FEMALE = 2;

// Other.
GENDER_OTHER = 3;
}

// Details about a single chat.
message Chat {
// The ID of the chat.
Expand All @@ -12,8 +27,11 @@ message Chat {
// The description of the chat.
string description = 2;

// The gender of the user initiaiting the chat.
Gender gender = 3;

// Details of CEOs to presented to the user in this chat.
repeated CEODetails ceo_details = 3;
repeated CEODetails ceo_details = 4;
}

// A request to get all chats.
Expand Down
300 changes: 189 additions & 111 deletions api/go/frontend.pb.go

Large diffs are not rendered by default.

54 changes: 52 additions & 2 deletions api/typescript/frontendapi/frontend_pb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,48 @@
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3 } from "@bufbuild/protobuf";

/**
* A user gender.
*
* @generated from enum frontendapi.Gender
*/
export enum Gender {
/**
* Gender has not been set.
*
* @generated from enum value: GENDER_UNSPECIFIED = 0;
*/
UNSPECIFIED = 0,

/**
* Male.
*
* @generated from enum value: GENDER_MALE = 1;
*/
MALE = 1,

/**
* Female.
*
* @generated from enum value: GENDER_FEMALE = 2;
*/
FEMALE = 2,

/**
* Other.
*
* @generated from enum value: GENDER_OTHER = 3;
*/
OTHER = 3,
}
// Retrieve enum metadata with: proto3.getEnumType(Gender)
proto3.util.setEnumType(Gender, "frontendapi.Gender", [
{ no: 0, name: "GENDER_UNSPECIFIED" },
{ no: 1, name: "GENDER_MALE" },
{ no: 2, name: "GENDER_FEMALE" },
{ no: 3, name: "GENDER_OTHER" },
]);

/**
* Details about a single chat.
*
Expand All @@ -26,10 +68,17 @@ export class Chat extends Message<Chat> {
*/
description = "";

/**
* The gender of the user initiaiting the chat.
*
* @generated from field: frontendapi.Gender gender = 3;
*/
gender = Gender.UNSPECIFIED;

/**
* Details of CEOs to presented to the user in this chat.
*
* @generated from field: repeated frontendapi.CEODetails ceo_details = 3;
* @generated from field: repeated frontendapi.CEODetails ceo_details = 4;
*/
ceoDetails: CEODetails[] = [];

Expand All @@ -43,7 +92,8 @@ export class Chat extends Message<Chat> {
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "description", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "ceo_details", kind: "message", T: CEODetails, repeated: true },
{ no: 3, name: "gender", kind: "enum", T: proto3.getEnumType(Gender) },
{ no: 4, name: "ceo_details", kind: "message", T: CEODetails, repeated: true },
]);

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Chat {
Expand Down
9 changes: 5 additions & 4 deletions client/src/components/ChatMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
ChatMessage as APIChatMessage,
CEODetails,
Gender,
} from "@aiceo/frontendapi";
import { Avatar } from "@nextui-org/avatar";
import { Button } from "@nextui-org/button";
Expand All @@ -9,16 +10,16 @@ import { forwardRef, useCallback } from "react";
import { twMerge } from "tailwind-merge";
import { navigate } from "vike/client/router";

import floormap from "@/assets/floormap.svg";
import thumbAICEO from "@/assets/thumb-aiceo.svg";
import { CEOS } from "@/data";

import { userThumbnail } from "@/data/user";
import { CEOAvatar } from "./CEOAvatar";
import { FloorMap } from "./FloorMap";

export interface ChatMessageProps {
message: APIChatMessage;
typeout?: boolean;
userGender?: Gender;
}

function CEOSnippet({
Expand Down Expand Up @@ -47,7 +48,7 @@ function CEOSnippet({
}

export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
function ChatMessage({ message }, ref) {
function ChatMessage({ userGender: gender, message }, ref) {
const onCeoClick = useCallback((ceo: CEODetails) => {
navigate(`/ceos/${ceo.key}?advice=${ceo.advice}&summary=${ceo.summary}`);
}, []);
Expand All @@ -63,7 +64,7 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
>
<Avatar
className="flex-none"
src={!message.isUser ? thumbAICEO : undefined}
src={!message.isUser ? thumbAICEO : userThumbnail(gender)}
/>
<div
className={twMerge(
Expand Down
18 changes: 18 additions & 0 deletions client/src/data/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Gender } from "@aiceo/frontendapi";

import youMan from "@/assets/you-man.svg";
import youOther from "@/assets/you-other.svg";
import youWoman from "@/assets/you-woman.svg";

export function userThumbnail(gender?: Gender): string | undefined {
switch (gender) {
case Gender.MALE:
return youMan;
case Gender.OTHER:
return youOther;
case Gender.FEMALE:
return youWoman;
default:
return undefined;
}
}
10 changes: 7 additions & 3 deletions client/src/pages/chats/+Page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { CEOS } from "@/data";
import { userThumbnail } from "@/data/user";
import { useFrontendQueries } from "@/hooks/rpc";
import { Avatar } from "@nextui-org/avatar";
import { useQuery } from "@tanstack/react-query";

export default function Page() {
Expand All @@ -22,11 +24,13 @@ export default function Page() {
<div className="flex justify-center">
<div className="flex flex-col gap-5">
{chatsRes.chats.map((chat) => (
<div key={chat.id} className="border-b-1">
<div className="text-2xl">{chat.description}</div>
<div key={chat.id}>
<div className="flex gap-3 items-center text-2xl mb-2">
<Avatar src={userThumbnail(chat.gender)} />
{chat.description}
</div>
<div className="flex flex-col md:flex-row gap-5">
{chat.ceoDetails.map((ceo) => {
console.log(ceo.key);
const ceoInfo = CEOS[ceo.key];
return (
<a
Expand Down
25 changes: 23 additions & 2 deletions client/src/pages/chats/@id/+Page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { GetChatMessagesResponse, sendMessage } from "@aiceo/frontendapi";
import {
Gender,
GetChatMessagesResponse,
sendMessage,
} from "@aiceo/frontendapi";
import { useMutation } from "@connectrpc/connect-query";
import { usePageContext } from "vike-react/usePageContext";

import { ChatMessage } from "@/components/ChatMessage";
import { useFrontendQueries } from "@/hooks/rpc";
import { Button } from "@nextui-org/button";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useCallback, useEffect, useRef } from "react";
import { useCallback, useEffect, useRef, useState } from "react";

type PressEvent = Parameters<
NonNullable<React.ComponentProps<typeof Button>["onPress"]>
Expand Down Expand Up @@ -45,6 +49,8 @@ export default function Page() {
lastMessageRef.current?.scrollIntoView();
});

const [gender, setGender] = useState(Gender.UNSPECIFIED);

if (isPending) {
// TODO: Better loading screen.
return <div>Loading...</div>;
Expand All @@ -54,6 +60,20 @@ export default function Page() {
throw new Error("Failed to load messages.");
}

if (gender === Gender.UNSPECIFIED && messagesRes.messages.length >= 3) {
switch (messagesRes.messages[2].message) {
case "男性":
setGender(Gender.MALE);
break;
case "女性":
setGender(Gender.FEMALE);
break;
case "その他":
setGender(Gender.OTHER);
break;
}
}

// We always start a chat with a message so there is no case where there are
// no messages.

Expand All @@ -65,6 +85,7 @@ export default function Page() {
{messagesRes.messages.map((msg, i) => (
<ChatMessage
key={msg.id}
userGender={gender}
message={msg}
ref={
i === messagesRes.messages.length - 1 ? lastMessageRef : undefined
Expand Down
14 changes: 14 additions & 0 deletions server/internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handler
import (
"context"
"fmt"
"slices"
"time"

"cloud.google.com/go/firestore"
Expand Down Expand Up @@ -31,6 +32,9 @@ func (h *Handler) GetChats(ctx context.Context, _ *frontendapi.GetChatsRequest)
if err != nil {
return nil, fmt.Errorf("handler: getting chats: %w", err)
}
slices.SortFunc(chatDocs, func(a, b *firestore.DocumentSnapshot) int {
return -a.CreateTime.Compare(b.CreateTime)
})

chats := make([]*frontendapi.Chat, 0, len(chatDocs))
for _, doc := range chatDocs {
Expand All @@ -50,10 +54,20 @@ func (h *Handler) GetChats(ctx context.Context, _ *frontendapi.GetChatsRequest)
if len(lastMsg.CEOs) == 0 {
continue
}
gender := frontendapi.Gender_GENDER_UNSPECIFIED
switch msgs[2].Data()["message"].(string) {
case "男性":
gender = frontendapi.Gender_GENDER_MALE
case "女性":
gender = frontendapi.Gender_GENDER_FEMALE
case "その他":
gender = frontendapi.Gender_GENDER_OTHER
}
desc := fmt.Sprintf("%s %s %s %s", msgs[2].Data()["message"], msgs[4].Data()["message"], msgs[6].Data()["message"], msgs[8].Data()["message"])
chats = append(chats, &frontendapi.Chat{
Id: doc.Ref.ID,
Description: desc,
Gender: gender,
CeoDetails: lastMsg.ToProto("").GetCeoDetails(),
})
}
Expand Down

0 comments on commit b6140d9

Please sign in to comment.