Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge main #11

Merged
merged 27 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
19b787e
add: profile page rebased
rishimohan Sep 25, 2023
ee11b3f
Merge pull request #6 from hive-one/add-profile-page-rebased
rishimohan Sep 25, 2023
01be727
chore: add build step to deploy
0xTiger Sep 25, 2023
b1fb032
trigger deploy
rishimohan Sep 25, 2023
6ef9b39
fix: fail action when script exits with nonzero code
0xTiger Sep 25, 2023
c4e09e7
Merge branch 'main' of https://github.com/hive-one/calcom into main
0xTiger Sep 25, 2023
4cfbc3c
fix: add firebase build args
0xTiger Sep 26, 2023
b477f0d
add: page to edit profile
rishimohan Sep 26, 2023
8cd113f
add: shadcdn and ui fixes
rishimohan Sep 26, 2023
3a1c4f9
simplified docker setup
danishabdullah Sep 27, 2023
d51d443
update the deploying to actually remove the previous services first
danishabdullah Sep 27, 2023
e7a4ee9
adding scripts directory back
danishabdullah Sep 27, 2023
9adb305
change timeout duration
danishabdullah Sep 27, 2023
2a527dc
use the correct directory
danishabdullah Sep 27, 2023
60caccc
build check is unnecessary
danishabdullah Sep 27, 2023
0de59cf
changing command timeout
danishabdullah Sep 27, 2023
01638d0
ssh command timeout
danishabdullah Sep 27, 2023
e6bef67
make sure start script is runnable
danishabdullah Sep 27, 2023
f754f13
update: onboarding options, redirection
rishimohan Sep 28, 2023
25c3a51
update: gate profile editing
rishimohan Sep 28, 2023
8c74366
Merge pull request #7 from hive-one/add-edit-profile
rishimohan Sep 28, 2023
00e9656
fix: rm directory before recreating
0xTiger Sep 29, 2023
f20bf75
fix: rm in correct action
0xTiger Sep 29, 2023
2587bca
update: branding and ux
rishimohan Sep 29, 2023
e1906b6
Merge pull request #8 from hive-one/more-updates
rishimohan Oct 4, 2023
4086010
feedback updates
rishimohan Oct 6, 2023
d88e292
Merge pull request #10 from hive-one/minor-updates
rishimohan Oct 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/deploy_production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:

jobs:
deploy_calcom:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -19,12 +20,19 @@ jobs:
key: ${{ secrets.CALCOM_SSH_KEY }}
source: "./, !.private"
target: "/home/deploy/calcom"
rm: true
- name: executing remote ssh commands using password
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.CALCOM_HOST }}
username: deploy
key: ${{ secrets.CALCOM_SSH_KEY }}
script_stop: true
command_timeout: 20m
script: |
cp .env calcom/.env
cp .env.appStore calcom/.env.appStore
cd calcom
DOCKER_BUILDKIT=0 docker-compose build
docker-compose down -v --remove-orphans
docker-compose up -d
65 changes: 24 additions & 41 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:18 as builder
FROM node:18

WORKDIR /calcom

Expand All @@ -8,67 +8,50 @@ ARG DATABASE_URL
ARG NEXTAUTH_SECRET=secret
ARG CALENDSO_ENCRYPTION_KEY=secret
ARG MAX_OLD_SPACE_SIZE=4096

ENV NEXT_PUBLIC_WEBAPP_URL=http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER \
ARG NEXT_PUBLIC_FIREBASE_API_KEY
ARG NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN
ARG NEXT_PUBLIC_FIREBASE_PROJECT_ID
ARG NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET
ARG NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID
ARG NEXT_PUBLIC_FIREBASE_APP_ID
ARG NEXT_PUBLIC_WEBAPP_URL

ENV NEXT_PUBLIC_WEBAPP_URL=${NEXT_PUBLIC_WEBAPP_URL} \
NEXT_PUBLIC_LICENSE_CONSENT=$NEXT_PUBLIC_LICENSE_CONSENT \
CALCOM_TELEMETRY_DISABLED=$CALCOM_TELEMETRY_DISABLED \
DATABASE_URL=$DATABASE_URL \
NEXTAUTH_SECRET=${NEXTAUTH_SECRET} \
CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY} \
NODE_OPTIONS=--max-old-space-size=${MAX_OLD_SPACE_SIZE}
NODE_OPTIONS=--max-old-space-size=${MAX_OLD_SPACE_SIZE} \
NEXT_PUBLIC_FIREBASE_API_KEY=${NEXT_PUBLIC_FIREBASE_API_KEY} \
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=${NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN} \
NEXT_PUBLIC_FIREBASE_PROJECT_ID=${NEXT_PUBLIC_FIREBASE_PROJECT_ID} \
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=${NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET} \
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=${NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID} \
NEXT_PUBLIC_FIREBASE_APP_ID=${NEXT_PUBLIC_FIREBASE_APP_ID} \
NODE_ENV=${NODE_ENV}

COPY package.json yarn.lock .yarnrc.yml playwright.config.ts turbo.json git-init.sh git-setup.sh ./
COPY .yarn ./.yarn
COPY tests ./tests
COPY apps/web ./apps/web
COPY apps/api ./apps/api
COPY packages ./packages
COPY scripts ./scripts

RUN yarn config set httpTimeout 1200000 && \
npx turbo prune --scope=@calcom/web --docker && \
yarn install && \
yarn db-deploy && \
yarn --cwd packages/prisma seed-app-store

RUN yarn turbo run build --filter=@calcom/web

# RUN yarn plugin import workspace-tools && \
# yarn workspaces focus --all --production
RUN rm -rf node_modules/.cache .yarn/cache apps/web/.next/cache

FROM node:18 as builder-two

ARG NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000

ENV NODE_ENV production

COPY package.json .yarnrc.yml yarn.lock turbo.json ./
COPY .yarn ./.yarn
COPY --from=builder /node_modules ./node_modules
COPY --from=builder /packages ./packages
COPY --from=builder /apps/web ./apps/web
COPY --from=builder /apps/api ./apps/api
COPY --from=builder /packages/prisma/schema.prisma ./prisma/schema.prisma
COPY scripts scripts
RUN yarn turbo run build --filter=@calcom/web && rm -rf node_modules/.cache .yarn/cache apps/web/.next/cache

# Save value used during this build stage. If NEXT_PUBLIC_WEBAPP_URL and BUILT_NEXT_PUBLIC_WEBAPP_URL differ at
# run-time, then start.sh will find/replace static values again.
ENV NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL \
BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL

RUN scripts/replace-placeholder.sh http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER ${NEXT_PUBLIC_WEBAPP_URL}

FROM node:18 as runner


COPY --from=builder-two / ./
ARG NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000
ENV NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL \
BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL

ENV NODE_ENV production
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=30s --retries=5 \
CMD wget --spider http://localhost:3000 || exit 1

CMD ["/scripts/start.sh"]
RUN chmod +x /calcom/scripts/start.sh

CMD ["/calcom/scripts/start.sh"]
16 changes: 16 additions & 0 deletions apps/web/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": false,
"tailwind": {
"config": "tailwind.config.js",
"css": "styles/globals.css",
"baseColor": "zinc",
"cssVariables": true
},
"aliases": {
"components": "shadcdn",
"utils": "shadcdn/utils"
}
}
48 changes: 48 additions & 0 deletions apps/web/components/edit-profile/Account/AdviceSection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { X } from "@phosphor-icons/react";
import { Input, Button, Label } from "@shadcdn/ui";

import EmptyState from "./EmptyState";
import FormBlock from "./FormBlock";

const AdviceSection = ({ profile, setProfile, addAdviceItem, removeAdviceItem }) => {
return (
<FormBlock title="Advice" description="What can you advise on? Add some topics you can help others with.">
{profile?.advice_on?.length === 0 && <EmptyState label="Things which you can advise others on" />}
<div className="space-y-4 divide-y">
{profile?.advice_on?.length > 0 &&
profile.advice_on.map((advice, i) => (
<div key={i} className="space-y-4 pt-2">
<div>
<Label>{`Advice #${i + 1}`}</Label>
<div className="flex items-end gap-x-2">
<Input
value={advice}
onChange={(e) => {
const newAdvice = [...profile.advice_on];
newAdvice[i] = e.target.value.slice(0, 100);
setProfile({ ...profile, advice_on: newAdvice });
}}
required
/>
<button
onClick={() => removeAdviceItem(i)}
type="button"
className="flex h-9 w-9 items-center justify-center rounded-md border border-rose-200 bg-rose-50 text-rose-500 hover:bg-rose-100">
<X className="h-5 w-5" />
</button>
</div>
<div className="mt-1 pr-12 text-right text-xs text-gray-400">{advice.length}/100</div>
</div>
</div>
))}
</div>
<div className="col-span-full mt-6">
<Button onClick={addAdviceItem} variant="outline" size="sm">
Add advice
</Button>
</div>
</FormBlock>
);
};

export default AdviceSection;
46 changes: 46 additions & 0 deletions apps/web/components/edit-profile/Account/BooksSection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Button, Input, Label } from "@shadcdn/ui";
import RemoveButton from "@ui/fayaz/RemoveButton";
import React from "react";

import EmptyState from "./EmptyState";
import FormBlock from "./FormBlock";

const BooksSection = ({ profile, setProfile, addBook, removeBook }) => {
return (
<FormBlock title="Books Published" description="Add details about books you've published">
{!profile?.books?.length > 0 && <EmptyState label="Add details about books you've published" />}
<div className="space-y-4 divide-y">
{profile?.books?.length > 0 &&
profile?.books?.map((book, i) => (
<div key={i} className="relative space-y-4 pt-4">
<div className="col-span-2">
<Label>ISBN</Label>
<Input
label="ISBN"
value={book.isbn}
onChange={(e) => {
const newBook = profile?.books?.length ? [...profile.books] : [];
newBook[i].isbn = e.target.value;
setProfile({
...profile,
books: newBook,
});
}}
/>
</div>
<div className="col-span-full flex items-center justify-end">
<RemoveButton label="Remove" onClick={() => removeBook(i)} />
</div>
</div>
))}
</div>
<div className="col-span-full mt-6">
<Button onClick={() => addBook("books")} variant="outline" size="sm">
Add section
</Button>
</div>
</FormBlock>
);
};

export default BooksSection;
106 changes: 106 additions & 0 deletions apps/web/components/edit-profile/Account/CalcomSetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { Button, Input, Label } from "@shadcdn/ui";
import Link from "next/link";
import { useState, useEffect } from "react";
import toast from "react-hot-toast";

import FormBlock from "./FormBlock";

async function getCalcomEvents(apiKey) {
const res = await fetch(`/api/calcom-events?apiKey=${apiKey}`);
const { events } = await res.json();
return events;
}

const CalcomSetup = ({ profile, setProfile }) => {
const [calcomEvents, setCalcomEvents] = useState([]);
const [apiKey, setApiKey] = useState("");
const [loading, setLoading] = useState(false);
const [selectedEvent, setSelectedEvent] = useState(null);

useEffect(() => {
const savedApiKey = profile.calendar?.calcom_api_key;
const savedEventId = profile.calendar?.calcom_event_id;
if (savedApiKey && savedEventId) {
getEvents(savedApiKey, savedEventId);
}
setApiKey(savedApiKey || "");
}, []);

const getEvents = async (apiKey, selectedEventId) => {
try {
setLoading(true);
const events = await getCalcomEvents(apiKey);
setCalcomEvents(events);
const selectedEvent = events.find((event) => event.id === selectedEventId);
setSelectedEvent(selectedEvent || null);
} catch (error) {
console.log(error);
toast.error("Something went wrong 😕");
} finally {
setLoading(false);
}
};

const handleGetEvents = async () => {
try {
setLoading(true);
const events = await getCalcomEvents(apiKey);
setCalcomEvents(events);
setSelectedEvent(events[0]);
} catch (error) {
console.log(error);
toast.error("Something went wrong 😕");
} finally {
setLoading(false);
}
};

const setEvent = (event) => {
setSelectedEvent(event);
const payload = {
calcom_event_name: event.title,
calcom_event_id: event.id,
calcom_event_url: event.link,
calcom_event_length: event.length,
calcom_api_key: apiKey,
};
setProfile({ ...profile, calendar: payload });
};

return (
<FormBlock title="Calendar">
<div className="flex flex-col gap-3">
<div>
<Label>Your Call booking link</Label>
<Input className="mt-2" value={profile?.calendar?.calcom_event_url} />
</div>
<div className="mt-5">
<Label>Setup you calendar and availibility</Label>
<p className="mt-3 text-sm text-gray-600">To connect your calendars and setup your availibility:</p>
<ul className="mt-3 list-disc space-y-1 pl-5 text-sm text-gray-600">
<li>
Head to your Calendars account{" "}
<Link
href="https://cal.borg.id/auth/login?callbackUrl=getting-started"
target="_blank"
className="underline">
using this link
</Link>
</li>
<li>Login with your Borg.id email and password</li>
<li>Connect your Google, Apple Calendar and other calendars</li>
<li>Setup slots and block the times you are not available</li>
<li>You&apos;re done! Your call link on Borg.id will automatically use your availibility</li>
</ul>
<Button variant="outline" size="sm" className="mt-5">
<Link href="https://cal.borg.id/auth/login" target="_blank">
Configure your calendar
</Link>
</Button>
</div>
</div>
</FormBlock>
);
};

export default CalcomSetup;
13 changes: 13 additions & 0 deletions apps/web/components/edit-profile/Account/EmptyState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";

const EmptyState = ({ label, children, helperText = "Click below to continue ↙" }) => {
return (
<div className="col-span-full flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed py-6">
<p className="text-sm font-medium text-gray-800">{label}</p>
<p className="text-sm text-gray-500">{helperText}</p>
{children}
</div>
);
};

export default EmptyState;
Loading
Loading