Skip to content

Commit

Permalink
Merge pull request #1780 from ever-co/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
evereq authored Nov 14, 2023
2 parents 717d4a7 + 0d859ec commit 9e3e8d5
Show file tree
Hide file tree
Showing 38 changed files with 710 additions and 356 deletions.
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ RUN apt-get update -qq && \
RUN npm install -g yarn --force

# Install node modules
COPY --link package.json ./
COPY --link yarn.lock ./
COPY --link apps/web/package.json ./apps/web/package.json
COPY package.json ./
COPY yarn.lock ./
COPY apps/web/package.json ./apps/web/package.json

RUN cd apps/web && \
yarn install --ignore-scripts

# Copy application code
COPY --link . .
COPY . .

ENV NODE_ENV=production

Expand Down
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: node apps/web/server.js
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ WIP

[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/ever-co/ever-teams)

### Heroku

[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)

## 📄 Content

- `/web` - NextJs-based (React) Web App at <https://app.ever.team> (deployed from `main` branch)
Expand Down
12 changes: 12 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "Ever Teams",
"description": "Open Work and Project Management Platform.",
"repository": "https://github.com/ever-co/ever-teams",
"logo": "https://raw.githubusercontent.com/ever-co/ever-teams/develop/apps/web/public/assets/ever-teams.png",
"keywords": [
"node",
"nextjs",
"tailwind"
],
"stack": "container"
}
13 changes: 8 additions & 5 deletions apps/mobile/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Config from "./config"
import { observer } from "mobx-react-lite"
import { initCrashReporting } from "./utils/crashReporting"
import FlashMessage from "react-native-flash-message"
import { ClickOutsideProvider } from "react-native-click-outside"

// Set up Reactotron, which is a free desktop app for inspecting and debugging
// React Native apps. Learn more here: https://github.com/infinitered/reactotron
Expand Down Expand Up @@ -94,11 +95,13 @@ const App = observer((props: AppProps) => {
<PaperProvider theme={theme}>
<ErrorBoundary catchErrors={Config.catchErrors}>
<FlashMessage position="top" />
<AppNavigator
theme={theme}
initialState={initialNavigationState}
onStateChange={onNavigationStateChange}
/>
<ClickOutsideProvider>
<AppNavigator
theme={theme}
initialState={initialNavigationState}
onStateChange={onNavigationStateChange}
/>
</ClickOutsideProvider>
</ErrorBoundary>
</PaperProvider>
</SafeAreaProvider>
Expand Down
9 changes: 8 additions & 1 deletion apps/mobile/app/components/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable react-native/no-color-literals */
/* eslint-disable react-native/no-inline-styles */
import { View, Text, StyleSheet, TouchableOpacity } from "react-native"
import React, { ReactElement, useState } from "react"
import React, { ReactElement, useState, useEffect } from "react"
import { Feather } from "@expo/vector-icons"
import { useAppTheme } from "../theme"

Expand All @@ -11,6 +11,7 @@ interface IAccordion {
titleFontSize?: number
arrowSize?: number
headerElement?: ReactElement
setAccordionExpanded?: (isExpanded: boolean) => void
}

const Accordion: React.FC<IAccordion> = ({
Expand All @@ -19,14 +20,20 @@ const Accordion: React.FC<IAccordion> = ({
arrowSize,
titleFontSize,
headerElement,
setAccordionExpanded,
}) => {
const [expanded, setExpanded] = useState(true)
const { colors } = useAppTheme()

function toggleItem() {
setExpanded(!expanded)
setAccordionExpanded && setAccordionExpanded(expanded)
}

useEffect(() => {
setAccordionExpanded && setAccordionExpanded(expanded)
}, [expanded])

const body = <View style={{ gap: 12 }}>{children}</View>
return (
<View style={[styles.accordContainer, { backgroundColor: colors.background }]}>
Expand Down
247 changes: 247 additions & 0 deletions apps/mobile/app/components/Task/DescrptionBlock/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/* eslint-disable react-native/no-inline-styles */
/* eslint-disable react-native/no-color-literals */
import { View, StyleSheet, TouchableOpacity, Text, TouchableWithoutFeedback } from "react-native"
import React, { RefObject } from "react"
import Accordion from "../../Accordion"
import QuillEditor, { QuillToolbar } from "react-native-cn-quill"
import { useStores } from "../../../models"
import { useAppTheme } from "../../../theme"
import { translate } from "../../../i18n"
import { SvgXml } from "react-native-svg"
import { copyIcon } from "../../svgs/icons"
import * as Clipboard from "expo-clipboard"
import { showMessage } from "react-native-flash-message"
import { useTeamTasks } from "../../../services/hooks/features/useTeamTasks"
import { useClickOutside } from "react-native-click-outside"

const DescriptionBlock = () => {
const _editor: RefObject<QuillEditor> = React.useRef()

const [editorKey, setEditorKey] = React.useState(1)
const [actionButtonsVisible, setActionButtonsVisible] = React.useState<boolean>(false)
const [accordionExpanded, setAccordionExpanded] = React.useState<boolean>(true)
const [htmlValue, setHtmlValue] = React.useState<string>("")

const { updateDescription } = useTeamTasks()

const {
TaskStore: { detailedTask: task },
} = useStores()

const { colors, dark } = useAppTheme()

React.useEffect(() => {
setEditorKey((prevKey) => prevKey + 1)
}, [colors, task?.description])

const handleHtmlChange = (html: string) => {
setHtmlValue(html)
}

function transformHtmlForSlate(html: string) {
// Replace <pre> with <p> and the content inside <pre> with <code>,
// excluding <a> tags from modification
const modifiedHtml = html
.replace(
/<pre class="ql-syntax" spellcheck="false">([\s\S]*?)<\/pre>/g,
(_, content) => {
const codeContent = content.replace(/(<a .*?<\/a>)/g, "PLACEHOLDER_FOR_A_TAG")
return `<p><pre><code>${codeContent}</code></pre></p>`
},
)
.replace(/PLACEHOLDER_FOR_A_TAG/g, (_, content) => content)
.replace(/class="ql-align-(.*?)"/g, (_, alignmentClass) => {
return `style="text-align:${alignmentClass}"`
})

return modifiedHtml
}

const onPressCancel = async (): Promise<void> => {
await _editor.current
.setContents("")
.then(() => _editor.current.dangerouslyPasteHTML(0, task?.description))
.then(() => _editor.current.blur())
.finally(() => setTimeout(() => setActionButtonsVisible(false), 100))
}

const onPressSave = async (): Promise<void> => {
const formattedValue = transformHtmlForSlate(htmlValue)
await updateDescription(formattedValue, task).finally(() => {
_editor.current.blur()
setActionButtonsVisible(false)
})
}

const copyDescription = async () => {
const descriptionPlainText = await _editor.current.getText()
Clipboard.setStringAsync(descriptionPlainText)
showMessage({
message: translate("taskDetailsScreen.copyDescription"),
type: "info",
backgroundColor: colors.secondary,
})
}

const editorContainerOutsidePressRef = useClickOutside<View>(() => {
_editor.current?.blur()
setActionButtonsVisible(false)
})
return (
<Accordion
setAccordionExpanded={setAccordionExpanded}
title={translate("taskDetailsScreen.description")}
headerElement={
accordionExpanded && (
<TouchableWithoutFeedback>
<TouchableOpacity onPress={copyDescription}>
<SvgXml xml={copyIcon} />
</TouchableOpacity>
</TouchableWithoutFeedback>
)
}
>
<View style={{ paddingBottom: 12 }} ref={editorContainerOutsidePressRef}>
<QuillEditor
key={editorKey}
style={styles.editor}
onHtmlChange={(event) => handleHtmlChange(event.html)}
onTextChange={() => setActionButtonsVisible(true)}
webview={{ allowsLinkPreview: true }}
ref={_editor}
initialHtml={task?.description ? task?.description : ""}
quill={{
placeholder: translate("taskDetailsScreen.descriptionBlockPlaceholder"),
modules: {
toolbar: false,
},
}}
theme={{
background: colors.background,
color: colors.primary,
placeholder: "#e0e0e0",
}}
/>

<View style={{ paddingHorizontal: 12 }}>
<View style={styles.horizontalSeparator} />
<QuillToolbar
editor={_editor}
styles={{
toolbar: {
provider: (provided) => ({
...provided,
borderTopWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
borderBottomWidth: 0,
}),
root: (provided) => ({
...provided,
backgroundColor: colors.background,
width: "100%",
}),
},
separator: (provided) => ({
...provided,
color: colors.secondary,
}),
selection: {
root: (provided) => ({
...provided,
backgroundColor: colors.background,
}),
},
}}
options={[
[
"bold",
"italic",
"underline",
"code",
"blockquote",

{ header: "1" },
{ header: "2" },
{ list: "ordered" },
{ list: "bullet" },
{ align: [] },
],
]}
theme={
dark
? {
background: "#1c1e21",
color: "#ebedf0",
overlay: "rgba(255, 255, 255, .15)",
size: 28,
}
: {
background: "#ebedf0",
color: "#1c1e21",
overlay: "rgba(55,99,115, .1)",
size: 28,
}
}
/>
{actionButtonsVisible && (
<View style={styles.actionButtonsWrapper}>
<TouchableOpacity
style={{
...styles.actionButton,
backgroundColor: "#E7E7EA",
}}
onPress={onPressCancel}
>
<Text style={{ fontSize: 12 }}>{translate("common.cancel")}</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={onPressSave}
style={{
...styles.actionButton,
backgroundColor: colors.secondary,
}}
>
<Text style={{ color: "white", fontSize: 12 }}>
{translate("common.save")}
</Text>
</TouchableOpacity>
</View>
)}
</View>
</View>
</Accordion>
)
}

export default DescriptionBlock

const styles = StyleSheet.create({
actionButton: {
alignItems: "center",
borderRadius: 8,
height: 30,
justifyContent: "center",
width: 80,
},
actionButtonsWrapper: {
flexDirection: "row",
gap: 5,
justifyContent: "flex-end",
marginVertical: 5,
},
editor: {
backgroundColor: "white",
borderWidth: 0,
flex: 1,
marginVertical: 5,
minHeight: 230,
padding: 0,
},
horizontalSeparator: {
borderTopColor: "#F2F2F2",
borderTopWidth: 1,
marginBottom: 10,
width: "100%",
},
})
17 changes: 16 additions & 1 deletion apps/mobile/app/components/Task/TimeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ interface ITotalGroupTime {

const TotalGroupTime: React.FC<ITotalGroupTime> = ({ totalTime, activeTeam, task }) => {
const [expanded, setExpanded] = useState(false)
const [numMembersToShow, setNumMembersToShow] = useState<number>(5)
const { colors } = useAppTheme()

function toggleItem() {
Expand Down Expand Up @@ -280,7 +281,7 @@ const TotalGroupTime: React.FC<ITotalGroupTime> = ({ totalTime, activeTeam, task
{expanded && <View style={{ marginBottom: 5 }} />}
<View style={{ gap: 7 }}>
{expanded &&
matchingMembers?.map((member, idx) => {
matchingMembers?.slice(0, numMembersToShow).map((member, idx) => {
const taskDurationInSeconds = findUserTotalWorked(member, task?.id)

const { h, m } = secondsToTime(taskDurationInSeconds)
Expand All @@ -297,6 +298,20 @@ const TotalGroupTime: React.FC<ITotalGroupTime> = ({ totalTime, activeTeam, task
/>
)
})}
{task?.members.length > 0 &&
task?.members?.length - 2 >= numMembersToShow &&
expanded && (
<TouchableOpacity
onPress={() => setNumMembersToShow((prev) => prev + 5)}
style={{ marginLeft: "auto" }}
>
<Text
style={{ fontSize: 10, fontWeight: "600", color: colors.primary }}
>
{translate("taskDetailsScreen.showMore")}
</Text>
</TouchableOpacity>
)}
</View>
</View>
)
Expand Down
Loading

0 comments on commit 9e3e8d5

Please sign in to comment.